Merge master.kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Tue, 21 Mar 2006 17:33:19 +0000 (09:33 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 21 Mar 2006 17:33:19 +0000 (09:33 -0800)
* master.kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6:
  [CRYPTO] aes: Fixed array boundary violation
  [CRYPTO] tcrypt: Fix key alignment
  [CRYPTO] all: Add missing cra_alignmask
  [CRYPTO] all: Use kzalloc where possible
  [CRYPTO] api: Align tfm context as wide as possible
  [CRYPTO] twofish: Use rol32/ror32 where appropriate

936 files changed:
.gitignore
CREDITS
Documentation/Changes
Documentation/connector/connector.txt
Documentation/dvb/avermedia.txt
Documentation/dvb/bt8xx.txt
Documentation/dvb/get_dvb_firmware
Documentation/dvb/readme.txt
Documentation/feature-removal-schedule.txt
Documentation/networking/ip-sysctl.txt
Documentation/usb/et61x251.txt
Documentation/usb/sn9c102.txt
Documentation/usb/zc0301.txt [new file with mode: 0644]
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/README.cpia2 [new file with mode: 0644]
Documentation/video4linux/cpia2_overview.txt [new file with mode: 0644]
MAINTAINERS
README
arch/arm/common/locomo.c
arch/arm/common/sa1111.c
arch/arm/mach-realview/core.c
arch/i386/defconfig
arch/m68knommu/kernel/vmlinux.lds.S
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/au1000/common/cputable.c
arch/mips/au1000/common/dbdma.c
arch/mips/au1000/common/dma.c
arch/mips/au1000/common/platform.c
arch/mips/au1000/common/setup.c
arch/mips/au1000/common/time.c
arch/mips/cobalt/Kconfig [new file with mode: 0644]
arch/mips/cobalt/Makefile
arch/mips/cobalt/console.c [new file with mode: 0644]
arch/mips/cobalt/setup.c
arch/mips/configs/atlas_defconfig
arch/mips/configs/bigsur_defconfig
arch/mips/configs/capcella_defconfig
arch/mips/configs/cobalt_defconfig
arch/mips/configs/db1000_defconfig
arch/mips/configs/db1100_defconfig
arch/mips/configs/db1200_defconfig
arch/mips/configs/db1500_defconfig
arch/mips/configs/db1550_defconfig
arch/mips/configs/ddb5476_defconfig
arch/mips/configs/ddb5477_defconfig
arch/mips/configs/decstation_defconfig
arch/mips/configs/e55_defconfig
arch/mips/configs/ev64120_defconfig
arch/mips/configs/ev96100_defconfig
arch/mips/configs/ip22_defconfig
arch/mips/configs/ip27_defconfig
arch/mips/configs/ip32_defconfig
arch/mips/configs/it8172_defconfig
arch/mips/configs/ivr_defconfig
arch/mips/configs/jaguar-atx_defconfig
arch/mips/configs/jmr3927_defconfig
arch/mips/configs/lasat200_defconfig
arch/mips/configs/malta_defconfig
arch/mips/configs/mipssim_defconfig
arch/mips/configs/mpc30x_defconfig
arch/mips/configs/ocelot_3_defconfig
arch/mips/configs/ocelot_c_defconfig
arch/mips/configs/ocelot_defconfig
arch/mips/configs/ocelot_g_defconfig
arch/mips/configs/pb1100_defconfig
arch/mips/configs/pb1500_defconfig
arch/mips/configs/pb1550_defconfig
arch/mips/configs/pnx8550-jbs_defconfig
arch/mips/configs/pnx8550-v2pci_defconfig
arch/mips/configs/qemu_defconfig
arch/mips/configs/rbhma4500_defconfig
arch/mips/configs/rm200_defconfig
arch/mips/configs/sb1250-swarm_defconfig
arch/mips/configs/sead_defconfig
arch/mips/configs/tb0226_defconfig
arch/mips/configs/tb0229_defconfig
arch/mips/configs/tb0287_defconfig [deleted file]
arch/mips/configs/workpad_defconfig
arch/mips/configs/yosemite_defconfig
arch/mips/dec/prom/memory.c
arch/mips/defconfig
arch/mips/jazz/int-handler.S
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/gdb-low.S
arch/mips/kernel/linux32.c
arch/mips/kernel/proc.c
arch/mips/kernel/process.c
arch/mips/kernel/setup.c
arch/mips/kernel/signal-common.h
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/mips/kernel/signal_n32.c
arch/mips/kernel/syscall.c
arch/mips/kernel/traps.c
arch/mips/lasat/image/romscript.normal
arch/mips/mips-boards/generic/mipsIRQ.S
arch/mips/mips-boards/sim/sim_IRQ.c
arch/mips/mips-boards/sim/sim_irq.S
arch/mips/mips-boards/sim/sim_smp.c
arch/mips/mm/Makefile
arch/mips/mm/c-r3k.c
arch/mips/mm/c-r4k.c
arch/mips/mm/pg-r4k.c
arch/mips/mm/sc-rm7k.c
arch/mips/mm/tlb-andes.c [deleted file]
arch/mips/mm/tlb-r4k.c
arch/mips/mm/tlbex.c
arch/mips/momentum/jaguar_atx/reset.c
arch/mips/momentum/jaguar_atx/setup.c
arch/mips/momentum/ocelot_3/reset.c
arch/mips/momentum/ocelot_c/reset.c
arch/mips/pci/fixup-vr4133.c
arch/mips/pci/ops-ddb5477.c
arch/mips/pci/ops-tx4938.c
arch/mips/pci/pci-bcm1480.c
arch/mips/pci/pci-bcm1480ht.c
arch/mips/pci/pci-ip27.c
arch/mips/philips/pnx8550/common/int.c
arch/mips/qemu/Makefile
arch/mips/qemu/q-smp.c [new file with mode: 0644]
arch/mips/sgi-ip27/ip27-memory.c
arch/mips/sgi-ip32/ip32-setup.c
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
arch/mips/tx4938/toshiba_rbtx4938/setup.c
arch/mips/vr41xx/common/bcu.c
arch/v850/kernel/vmlinux.lds.S
block/genhd.c
drivers/atm/suni.c
drivers/base/cpu.c
drivers/base/firmware_class.c
drivers/base/map.c
drivers/base/platform.c
drivers/block/ub.c
drivers/char/Makefile
drivers/char/drm/Kconfig
drivers/char/ip2/Makefile [new file with mode: 0644]
drivers/char/ip2/ip2base.c [moved from drivers/char/ip2.c with 95% similarity]
drivers/char/ip2/ip2main.c [moved from drivers/char/ip2main.c with 99% similarity]
drivers/char/s3c2410-rtc.c
drivers/char/watchdog/mpcore_wdt.c
drivers/connector/connector.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/ide/mips/au1xxx-ide.c
drivers/infiniband/core/agent.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/fmr_pool.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/mad_priv.h
drivers/infiniband/core/mad_rmpp.c
drivers/infiniband/core/smi.h
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/mthca/mthca_av.c
drivers/infiniband/hw/mthca/mthca_cmd.c
drivers/infiniband/hw/mthca/mthca_cmd.h
drivers/infiniband/hw/mthca/mthca_cq.c
drivers/infiniband/hw/mthca/mthca_dev.h
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/mthca/mthca_mad.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/mthca/mthca_mcg.c
drivers/infiniband/hw/mthca/mthca_memfree.c
drivers/infiniband/hw/mthca/mthca_memfree.h
drivers/infiniband/hw/mthca/mthca_mr.c
drivers/infiniband/hw/mthca/mthca_pd.c
drivers/infiniband/hw/mthca/mthca_profile.c
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/mthca/mthca_provider.h
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c
drivers/infiniband/hw/mthca/mthca_user.h
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/infiniband/ulp/ipoib/ipoib_verbs.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/media/common/Makefile
drivers/media/common/ir-common.c [deleted file]
drivers/media/common/ir-functions.c [new file with mode: 0644]
drivers/media/common/ir-keymaps.c [new file with mode: 0644]
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_i2c.c
drivers/media/common/saa7146_vbi.c
drivers/media/common/saa7146_video.c
drivers/media/dvb/b2c2/flexcop-common.h
drivers/media/dvb/b2c2/flexcop-i2c.c
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_ca.c
drivers/media/dvb/bt8xx/dst_common.h
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/bt8xx/dvb-bt8xx.h
drivers/media/dvb/cinergyT2/cinergyT2.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dmxdev.h
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_demux.h
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-core/dvb_ringbuffer.c
drivers/media/dvb/dvb-core/dvb_ringbuffer.h
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dvb-usb-init.c
drivers/media/dvb/dvb-usb/dvb-usb-urb.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/vp702x.c
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/bcm3510.c
drivers/media/dvb/frontends/bsbe1.h [new file with mode: 0644]
drivers/media/dvb/frontends/bsru6.h [new file with mode: 0644]
drivers/media/dvb/frontends/cx24110.c
drivers/media/dvb/frontends/cx24110.h
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/lnbp21.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/frontends/tda1004x.h
drivers/media/dvb/frontends/zl10353.c [new file with mode: 0644]
drivers/media/dvb/frontends/zl10353.h [new file with mode: 0644]
drivers/media/dvb/frontends/zl10353_priv.h [new file with mode: 0644]
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/av7110_hw.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-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/radio/miropcm20-rds-core.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-maestro.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/bttv-cards.c
drivers/media/video/bttv-driver.c
drivers/media/video/bttv-input.c
drivers/media/video/bttv-risc.c
drivers/media/video/bw-qcam.c
drivers/media/video/bw-qcam.h
drivers/media/video/c-qcam.c
drivers/media/video/cpia.c
drivers/media/video/cpia.h
drivers/media/video/cpia2/Kconfig [new file with mode: 0644]
drivers/media/video/cpia2/Makefile [new file with mode: 0644]
drivers/media/video/cpia2/cpia2.h [new file with mode: 0644]
drivers/media/video/cpia2/cpia2_core.c [new file with mode: 0644]
drivers/media/video/cpia2/cpia2_registers.h [new file with mode: 0644]
drivers/media/video/cpia2/cpia2_usb.c [new file with mode: 0644]
drivers/media/video/cpia2/cpia2_v4l.c [new file with mode: 0644]
drivers/media/video/cpia2/cpia2dev.h [new file with mode: 0644]
drivers/media/video/cpia2/cpia2patch.h [new file with mode: 0644]
drivers/media/video/cx25840/Kconfig [new file with mode: 0644]
drivers/media/video/cx25840/Makefile
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx25840/cx25840.h
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/Makefile
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/dpc7146.c
drivers/media/video/em28xx/Kconfig
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/hexium_gemini.c
drivers/media/video/hexium_orion.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/meye.c
drivers/media/video/meye.h
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-kthreads.c
drivers/media/video/msp3400.h
drivers/media/video/mxb.c
drivers/media/video/mxb.h
drivers/media/video/planb.c
drivers/media/video/planb.h
drivers/media/video/pms.c
drivers/media/video/saa5246a.c
drivers/media/video/saa5249.c
drivers/media/video/saa7115.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-oss.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/tda8290.c
drivers/media/video/tda9840.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-simple.c
drivers/media/video/tuner-types.c
drivers/media/video/tvaudio.c
drivers/media/video/tvp5150.c
drivers/media/video/tvp5150_reg.h
drivers/media/video/v4l2-common.c
drivers/media/video/video-buf-dvb.c
drivers/media/video/video-buf.c
drivers/media/video/videodev.c
drivers/media/video/vino.c
drivers/mmc/pxamci.c
drivers/net/8139too.c
drivers/net/arm/am79c961a.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/cassini.c
drivers/net/cassini.h
drivers/net/e1000/e1000_main.c
drivers/net/fs_enet/mac-fcc.c
drivers/net/fs_enet/mac-fec.c
drivers/net/fs_enet/mac-scc.c
drivers/net/gianfar.c
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/donauboe.c
drivers/net/irda/ep7211_ir.c
drivers/net/irda/irda-usb.c
drivers/net/irda/irtty-sir.c
drivers/net/irda/nsc-ircc.c
drivers/net/irda/nsc-ircc.h
drivers/net/irda/sir_dongle.c
drivers/net/irda/toim3232-sir.c [new file with mode: 0644]
drivers/net/irda/vlsi_ir.c
drivers/net/ppp_generic.c
drivers/net/pppoe.c
drivers/net/smc91x.c
drivers/net/sungem.c
drivers/net/sungem.h
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/wan/sbni.c
drivers/pcmcia/omap_cf.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/ahci.c
drivers/scsi/ata_piix.c
drivers/scsi/libata-bmdma.c [new file with mode: 0644]
drivers/scsi/libata-core.c
drivers/scsi/libata-scsi.c
drivers/scsi/libata.h
drivers/scsi/pdc_adma.c
drivers/scsi/sata_mv.c
drivers/scsi/sata_nv.c
drivers/scsi/sata_promise.c
drivers/scsi/sata_qstor.c
drivers/scsi/sata_sil.c
drivers/scsi/sata_sil24.c
drivers/scsi/sata_sis.c
drivers/scsi/sata_svw.c
drivers/scsi/sata_sx4.c
drivers/scsi/sata_uli.c
drivers/scsi/sata_via.c
drivers/scsi/sata_vsc.c
drivers/scsi/scsi_error.c
drivers/serial/s3c2410.c
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/class/Kconfig
drivers/usb/class/Makefile
drivers/usb/class/audio.c [deleted file]
drivers/usb/class/audio.h [deleted file]
drivers/usb/class/cdc-acm.c
drivers/usb/class/usb-midi.c [deleted file]
drivers/usb/class/usb-midi.h [deleted file]
drivers/usb/class/usblp.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/notify.c
drivers/usb/core/usb.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/at91_udc.c [new file with mode: 0644]
drivers/usb/gadget/at91_udc.h [new file with mode: 0644]
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/lh7a40x_udc.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c [new file with mode: 0644]
drivers/usb/host/ehci-fsl.c [new file with mode: 0644]
drivers/usb/host/ehci-fsl.h [new file with mode: 0644]
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-mem.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h
drivers/usb/host/hc_crisv10.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-at91.c [new file with mode: 0644]
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-hub.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-hub.c
drivers/usb/host/uhci-q.c
drivers/usb/image/mdc800.c
drivers/usb/input/ati_remote.c
drivers/usb/input/hid-core.c
drivers/usb/input/hid-lgff.c
drivers/usb/input/hid-tmff.c
drivers/usb/input/hid.h
drivers/usb/input/hiddev.c
drivers/usb/media/Kconfig
drivers/usb/media/Makefile
drivers/usb/media/dabusb.c
drivers/usb/media/dabusb.h
drivers/usb/media/et61x251.h
drivers/usb/media/et61x251_core.c
drivers/usb/media/et61x251_sensor.h
drivers/usb/media/et61x251_tas5130d1b.c
drivers/usb/media/ov511.c
drivers/usb/media/ov511.h
drivers/usb/media/pwc/pwc-ctrl.c
drivers/usb/media/pwc/pwc-if.c
drivers/usb/media/se401.c
drivers/usb/media/se401.h
drivers/usb/media/sn9c102.h
drivers/usb/media/sn9c102_core.c
drivers/usb/media/sn9c102_ov7630.c
drivers/usb/media/sn9c102_pas202bca.c [new file with mode: 0644]
drivers/usb/media/sn9c102_pas202bcb.c
drivers/usb/media/sn9c102_sensor.h
drivers/usb/media/sn9c102_tas5110c1b.c
drivers/usb/media/sn9c102_tas5130d1b.c
drivers/usb/media/stv680.c
drivers/usb/media/stv680.h
drivers/usb/media/usbvideo.c
drivers/usb/media/usbvideo.h
drivers/usb/media/vicam.c
drivers/usb/media/w9968cf.c
drivers/usb/media/w9968cf.h
drivers/usb/media/zc0301.h [new file with mode: 0644]
drivers/usb/media/zc0301_core.c [new file with mode: 0644]
drivers/usb/media/zc0301_pas202bcb.c [new file with mode: 0644]
drivers/usb/media/zc0301_sensor.h [new file with mode: 0644]
drivers/usb/misc/auerswald.c
drivers/usb/misc/cytherm.c
drivers/usb/misc/idmouse.c
drivers/usb/misc/ldusb.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/phidgetkit.c
drivers/usb/misc/phidgetservo.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb.h
drivers/usb/misc/usblcd.c
drivers/usb/misc/usbled.c
drivers/usb/misc/usbtest.c
drivers/usb/mon/mon_main.c
drivers/usb/mon/mon_text.c
drivers/usb/mon/usb_mon.h
drivers/usb/net/pegasus.c
drivers/usb/net/pegasus.h
drivers/usb/net/rtl8150.c
drivers/usb/net/zd1201.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/cp2101.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/cypress_m8.h
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/navman.c [new file with mode: 0644]
drivers/usb/serial/omninet.c
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/storage/datafab.c
drivers/usb/storage/isd200.c
drivers/usb/storage/jumpshot.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/sddr55.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/storage/usb.h
drivers/video/Kconfig
drivers/video/epson1355fb.c
drivers/video/sa1100fb.c
drivers/video/vfb.c
fs/char_dev.c
fs/debugfs/file.c
fs/sysfs/dir.c
fs/sysfs/file.c
fs/sysfs/inode.c
fs/sysfs/symlink.c
fs/sysfs/sysfs.h
include/asm-arm/irq.h
include/asm-generic/vmlinux.lds.h
include/asm-mips/byteorder.h
include/asm-mips/compat.h
include/asm-mips/io.h
include/asm-mips/mach-cobalt/cobalt.h
include/asm-mips/mach-generic/mangle-port.h
include/asm-mips/mach-ip27/mangle-port.h
include/asm-mips/mach-ip32/mangle-port.h
include/asm-mips/mach-mips/cpu-feature-overrides.h
include/asm-mips/mmu_context.h
include/asm-mips/pgtable-32.h
include/asm-mips/r4kcache.h
include/asm-mips/signal.h
include/asm-mips/sn/klconfig.h
include/asm-mips/sn/mapped_kernel.h
include/asm-mips/sn/sn0/hubio.h
include/asm-mips/stackframe.h
include/asm-mips/system.h
include/asm-mips/thread_info.h
include/asm-sparc/socket.h
include/linux/amba/clcd.h
include/linux/ata.h
include/linux/cpu.h
include/linux/dccp.h
include/linux/debugfs.h
include/linux/device.h
include/linux/dn.h
include/linux/dvb/audio.h
include/linux/dvb/video.h
include/linux/fsl_devices.h
include/linux/icmpv6.h
include/linux/if.h
include/linux/in.h
include/linux/inetdevice.h
include/linux/ipv6.h
include/linux/ipv6_route.h
include/linux/irda.h
include/linux/kobj_map.h
include/linux/kobject.h
include/linux/libata.h
include/linux/list.h
include/linux/module.h
include/linux/net.h
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/netfilter/nfnetlink.h
include/linux/netfilter/nfnetlink_log.h
include/linux/netfilter/x_tables.h
include/linux/netfilter/xt_policy.h [new file with mode: 0644]
include/linux/netfilter_bridge.h
include/linux/netfilter_ipv4/ip_conntrack.h
include/linux/netfilter_ipv4/ip_conntrack_h323.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ip_nat.h
include/linux/netfilter_ipv4/ipt_policy.h
include/linux/netfilter_ipv6/ip6t_policy.h
include/linux/netlink.h
include/linux/pci_ids.h
include/linux/rtnetlink.h
include/linux/security.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/sunrpc/svcsock.h
include/linux/sysctl.h
include/linux/tcp.h
include/linux/usb.h
include/linux/usb_gadget.h
include/linux/videodev2.h
include/linux/xfrm.h
include/media/ir-common.h
include/media/saa7146.h
include/media/tuner-types.h
include/media/tuner.h
include/media/v4l2-common.h
include/media/video-buf-dvb.h
include/media/video-buf.h
include/net/af_unix.h
include/net/dn.h
include/net/dn_dev.h
include/net/dn_fib.h
include/net/dn_neigh.h
include/net/dn_nsp.h
include/net/dn_route.h
include/net/flow.h
include/net/if_inet6.h
include/net/inet_connection_sock.h
include/net/ip.h
include/net/ip6_route.h
include/net/ipv6.h
include/net/llc.h
include/net/ndisc.h
include/net/neighbour.h
include/net/netfilter/nf_conntrack.h
include/net/scm.h
include/net/sctp/structs.h
include/net/sock.h
include/net/tcp.h
include/net/xfrm.h
include/rdma/ib_fmr_pool.h
include/rdma/ib_mad.h
include/rdma/ib_user_verbs.h
include/rdma/ib_verbs.h
include/scsi/scsi_eh.h
kernel/ksysfs.c
kernel/module.c
kernel/params.c
kernel/rcupdate.c
lib/kobject.c
lib/kobject_uevent.c
lib/kref.c
net/802/psnap.c
net/8021q/vlan.c
net/8021q/vlan_dev.c
net/atm/clip.c
net/atm/common.c
net/atm/ioctl.c
net/atm/resources.c
net/atm/resources.h
net/bluetooth/rfcomm/core.c
net/bridge/Kconfig
net/bridge/br.c
net/bridge/br_device.c
net/bridge/br_fdb.c
net/bridge/br_if.c
net/bridge/br_input.c
net/bridge/br_netfilter.c
net/bridge/br_private.h
net/bridge/br_stp_bpdu.c
net/bridge/br_stp_timer.c
net/bridge/br_sysfs_br.c
net/bridge/netfilter/ebtables.c
net/compat.c
net/core/dev.c
net/core/flow.c
net/core/link_watch.c
net/core/neighbour.c
net/core/net-sysfs.c
net/core/netpoll.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/dccp/Kconfig
net/dccp/Makefile
net/dccp/ackvec.c
net/dccp/ackvec.h
net/dccp/ccid.c
net/dccp/ccid.h
net/dccp/ccids/Kconfig
net/dccp/ccids/Makefile
net/dccp/ccids/ccid2.c [new file with mode: 0644]
net/dccp/ccids/ccid2.h [new file with mode: 0644]
net/dccp/ccids/ccid3.c
net/dccp/ccids/ccid3.h
net/dccp/dccp.h
net/dccp/diag.c
net/dccp/feat.c [new file with mode: 0644]
net/dccp/feat.h [new file with mode: 0644]
net/dccp/input.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dccp/minisocks.c
net/dccp/options.c
net/dccp/output.c
net/dccp/proto.c
net/dccp/sysctl.c [new file with mode: 0644]
net/dccp/timer.c
net/decnet/af_decnet.c
net/decnet/dn_dev.c
net/decnet/dn_fib.c
net/decnet/dn_neigh.c
net/decnet/dn_nsp_in.c
net/decnet/dn_nsp_out.c
net/decnet/dn_route.c
net/decnet/dn_rules.c
net/decnet/dn_table.c
net/decnet/sysctl_net_decnet.c
net/ipv4/af_inet.c
net/ipv4/ah4.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/fib_rules.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/ip_sockglue.c
net/ipv4/ipcomp.c
net/ipv4/ipconfig.c
net/ipv4/ipmr.c
net/ipv4/ipvs/ip_vs_app.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/arpt_mangle.c
net/ipv4/netfilter/ip_conntrack_helper_h323.c [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_helper_h323_types.c [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_helper_h323_types.h [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_netlink.c
net/ipv4/netfilter/ip_nat_helper_h323.c [new file with mode: 0644]
net/ipv4/netfilter/ip_nat_helper_pptp.c
net/ipv4/netfilter/ip_nat_rule.c
net/ipv4/netfilter/ip_nat_snmp_basic.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/ipt_DSCP.c
net/ipv4/netfilter/ipt_ECN.c
net/ipv4/netfilter/ipt_LOG.c
net/ipv4/netfilter/ipt_MASQUERADE.c
net/ipv4/netfilter/ipt_NETMAP.c
net/ipv4/netfilter/ipt_REDIRECT.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/ipt_SAME.c
net/ipv4/netfilter/ipt_TCPMSS.c
net/ipv4/netfilter/ipt_TOS.c
net/ipv4/netfilter/ipt_TTL.c
net/ipv4/netfilter/ipt_ULOG.c
net/ipv4/netfilter/ipt_addrtype.c
net/ipv4/netfilter/ipt_ah.c
net/ipv4/netfilter/ipt_dscp.c
net/ipv4/netfilter/ipt_ecn.c
net/ipv4/netfilter/ipt_esp.c
net/ipv4/netfilter/ipt_hashlimit.c
net/ipv4/netfilter/ipt_iprange.c
net/ipv4/netfilter/ipt_multiport.c
net/ipv4/netfilter/ipt_owner.c
net/ipv4/netfilter/ipt_policy.c [deleted file]
net/ipv4/netfilter/ipt_recent.c
net/ipv4/netfilter/ipt_tos.c
net/ipv4/netfilter/ipt_ttl.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/raw.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/udp.c
net/ipv4/xfrm4_tunnel.c
net/ipv6/Kconfig
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ah6.c
net/ipv6/anycast.c
net/ipv6/esp6.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_output.c
net/ipv6/ipcomp6.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6t_HL.c
net/ipv6/netfilter/ip6t_LOG.c
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/netfilter/ip6t_ah.c
net/ipv6/netfilter/ip6t_dst.c
net/ipv6/netfilter/ip6t_esp.c
net/ipv6/netfilter/ip6t_eui64.c
net/ipv6/netfilter/ip6t_frag.c
net/ipv6/netfilter/ip6t_hbh.c
net/ipv6/netfilter/ip6t_hl.c
net/ipv6/netfilter/ip6t_ipv6header.c
net/ipv6/netfilter/ip6t_multiport.c
net/ipv6/netfilter/ip6t_owner.c
net/ipv6/netfilter/ip6t_policy.c [deleted file]
net/ipv6/netfilter/ip6t_rt.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_tunnel.c
net/key/af_key.c
net/llc/af_llc.c
net/llc/llc_c_ac.c
net/llc/llc_core.c
net/llc/llc_output.c
net/llc/llc_output.h [deleted file]
net/llc/llc_s_ac.c
net/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_sockopt.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_log.c
net/netfilter/x_tables.c
net/netfilter/xt_CLASSIFY.c
net/netfilter/xt_CONNMARK.c
net/netfilter/xt_MARK.c
net/netfilter/xt_NFQUEUE.c
net/netfilter/xt_NOTRACK.c
net/netfilter/xt_comment.c
net/netfilter/xt_connbytes.c
net/netfilter/xt_connmark.c
net/netfilter/xt_conntrack.c
net/netfilter/xt_dccp.c
net/netfilter/xt_helper.c
net/netfilter/xt_length.c
net/netfilter/xt_limit.c
net/netfilter/xt_mac.c
net/netfilter/xt_mark.c
net/netfilter/xt_physdev.c
net/netfilter/xt_pkttype.c
net/netfilter/xt_policy.c [new file with mode: 0644]
net/netfilter/xt_realm.c
net/netfilter/xt_sctp.c
net/netfilter/xt_state.c
net/netfilter/xt_string.c
net/netfilter/xt_tcpmss.c
net/netfilter/xt_tcpudp.c
net/netlink/af_netlink.c
net/sched/Kconfig
net/sched/act_ipt.c
net/sched/sch_atm.c
net/sched/sch_dsmark.c
net/sched/sch_generic.c
net/sched/sch_netem.c
net/sched/sch_prio.c
net/sched/sch_red.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c
net/sctp/ipv6.c
net/sctp/protocol.c
net/socket.c
net/sunrpc/cache.c
net/sunrpc/sched.c
net/sunrpc/svcsock.c
net/tipc/bcast.c
net/tipc/bearer.c
net/tipc/cluster.c
net/tipc/cluster.h
net/tipc/config.c
net/tipc/dbg.c
net/tipc/discover.c
net/tipc/eth_media.c
net/tipc/link.c
net/tipc/name_distr.c
net/tipc/name_table.c
net/tipc/net.c
net/tipc/node.c
net/tipc/node.h
net/tipc/node_subscr.c
net/tipc/port.c
net/tipc/ref.c
net/tipc/ref.h
net/tipc/socket.c
net/tipc/subscr.c
net/tipc/user_reg.c
net/tipc/zone.c
net/unix/af_unix.c
net/unix/garbage.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
scripts/genksyms/keywords.c_shipped
scripts/genksyms/keywords.gperf
security/dummy.c
security/selinux/hooks.c
security/selinux/include/xfrm.h
security/selinux/nlmsgtab.c
security/selinux/xfrm.c

index 3f8fb68..53e53f2 100644 (file)
@@ -30,3 +30,5 @@ include/linux/autoconf.h
 include/linux/compile.h
 include/linux/version.h
 
+# stgit generated dirs
+patches-*
diff --git a/CREDITS b/CREDITS
index 1f171f1..af70678 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2813,6 +2813,8 @@ E: luca.risolia@studio.unibo.it
 P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4
 D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
 D: V4L2 driver for SN9C10x PC Camera Controllers
+D: V4L2 driver for ET61X151 and ET61X251 PC Camera Controllers
+D: V4L2 driver for ZC0301 Image Processor and Control Chip
 S: Via Liberta' 41/A
 S: Osio Sotto, 24046, Bergamo
 S: Italy
index fe5ae0f..b02f476 100644 (file)
@@ -15,24 +15,6 @@ and therefore owes credit to the same people as that file (Jared Mauch,
 Axel Boldt, Alessandro Sigala, and countless other users all over the
 'net).
 
-The latest revision of this document, in various formats, can always
-be found at <http://cyberbuzz.gatech.edu/kaboom/linux/Changes-2.4/>.
-
-Feel free to translate this document.  If you do so, please send me a
-URL to your translation for inclusion in future revisions of this
-document.
-
-Smotrite file <http://oblom.rnc.ru/linux/kernel/Changes.ru>, yavlyaushisya
-russkim perevodom dannogo documenta.
-
-Visite <http://www2.adi.uam.es/~ender/tecnico/> para obtener la traducción
-al español de este documento en varios formatos.
-
-Eine deutsche Version dieser Datei finden Sie unter
-<http://www.stefan-winter.de/Changes-2.4.0.txt>.
-
-Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
-
 Current Minimal Requirements
 ============================
 
index 57a314b..ad6e0ba 100644 (file)
@@ -69,10 +69,11 @@ Unregisters new callback with connector core.
 
 struct cb_id *id               - unique connector's user identifier.
 
-void cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
+int cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
 
 Sends message to the specified groups.  It can be safely called from
-any context, but may silently fail under strong memory pressure.
+softirq context, but may silently fail under strong memory pressure.
+If there are no listeners for given group -ESRCH can be returned.
 
 struct cn_msg *                        - message header(with attached data).
 u32 __group                    - destination group.
index 068070f..8bab846 100644 (file)
@@ -1,4 +1,3 @@
-
 HOWTO: Get An Avermedia DVB-T working under Linux
           ______________________________________________
 
@@ -137,11 +136,8 @@ Getting the card going
    To  power  up  the  card,  load  the  following modules in the
    following order:
 
-     * insmod dvb-core.o
-     * modprobe bttv.o
-     * insmod bt878.o
-     * insmod dvb-bt8xx.o
-     * insmod sp887x.o
+     * modprobe bttv (normally loaded automatically)
+     * modprobe dvb-bt8xx (or place dvb-bt8xx in /etc/modules)
 
    Insertion  of  these  modules  into  the  running  kernel will
    activate the appropriate DVB device nodes. It is then possible
@@ -302,4 +298,4 @@ Further Update
    Many  thanks to Nigel Pearson for the updates to this document
    since the recent revision of the driver.
 
-   January 29th 2004
+   February 14th 2006
index 52ed462..4e7614e 100644 (file)
-How to get the Nebula, PCTV, FusionHDTV Lite and Twinhan DST cards working
-==========================================================================
+How to get the bt8xx cards working
+==================================
 
-This class of cards has a bt878a as the PCI interface, and
-require the bttv driver.
+1) General information
+======================
 
-Please pay close attention to the warning about the bttv module
-options below for the DST card.
+This class of cards has a bt878a as the PCI interface, and require the bttv driver
+for accessing the i2c bus and the gpio pins of the bt8xx chipset.
+Please see Documentation/dvb/cards.txt => o Cards based on the Conexant Bt8xx PCI bridge:
 
-1) General informations
-=======================
-
-These drivers require the bttv driver to provide the means to access
-the i2c bus and the gpio pins of the bt8xx chipset.
-
-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" "BT8xx based PCI cards"
+Compiling kernel please enable:
+a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "BT848 Video For Linux"
+b.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
 
 2) Loading Modules
 ==================
 
-In general you need to load the bttv driver, which will handle the gpio and
-i2c communication for us, plus the common dvb-bt8xx device driver.
-The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110), TwinHan (dst),
-FusionHDTV DVB-T Lite (mt352) and FusionHDTV5 Lite (lgdt330x) are loaded
-automatically by the dvb-bt8xx device driver.
-
-3a) Nebula / Pinnacle PCTV / FusionHDTV Lite
----------------------------------------------
-
-   $ modprobe bttv (normally bttv is being loaded automatically by kmod)
-   $ modprobe dvb-bt8xx
-
-(or just place dvb-bt8xx in /etc/modules for automatic loading)
-
-
-3b) TwinHan and Clones
---------------------------
+In default cases bttv is loaded automatically.
+To load the backend either place dvb-bt8xx in etc/modules, or apply manually:
 
-   $ modprobe bttv card=0x71
-   $ modprobe dvb-bt8xx
-   $ modprobe dst
+       $ modprobe dvb-bt8xx
 
-The value 0x71 will override the PCI type detection for dvb-bt8xx,
-which  is necessary for TwinHan cards. Omission of this parameter might result
-in a system lockup.
+All frontends will be loaded automatically.
+People running udev please see Documentation/dvb/udev.txt.
 
-If you're having an older card (blue color PCB) and card=0x71 locks up
-your machine, try using 0x68, too. If that does not work, ask on the
-mailing list.
+In the following cases overriding the PCI type detection for dvb-bt8xx might be necessary:
 
-The DST module takes a couple of useful parameters.
+2a) Running TwinHan and Clones
+------------------------------
 
-verbose takes values 0 to 4. These values control the verbosity level,
-and can be used to debug also.
+       $ modprobe bttv card=113
+       $ modprobe dvb-bt8xx
+       $ modprobe dst
 
-verbose=0 means complete disabling of messages
-       1 only error messages are displayed
-       2 notifications are also displayed
-       3 informational messages are also displayed
-       4 debug setting
+Useful parameters for verbosity level and debugging the dst module:
 
-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.
+verbose=0:             messages are disabled
+       1:              only error messages are displayed
+       2:              notifications are displayed
+       3:              other useful messages are displayed
+       4:              debug setting
+dst_addons=0:          card is a free to air (FTA) card only
+          0x20:        card has a conditional access slot for scrambled channels
 
-The autodetected values are determined by the cards 'response string'
-which you can see in your logs e.g.
+The autodetected values are determined by the cards' "response string".
+In your logs see f. ex.: dst_get_device_id: Recognize [DSTMCI].
+For bug reports please send in a complete log with verbose=4 activated.
+Please also see Documentation/dvb/ci.txt.
 
-dst_get_device_id: Recognise [DSTMCI]
-
-If you need to sent in bug reports on the dst, please do send in a complete
-log with the verbose=4 module parameter. For general usage, the default setting
-of verbose=1 is ideal.
-
-
-4) Multiple cards
+2b) Running multiple cards
 --------------------------
 
-If you happen to be running multiple cards, it would be advisable to load
-the bttv module with the card id. This would help to solve any module loading
-problems that you might face.
-
-For example, if you have a Twinhan and Clones card along with a FusionHDTV5 Lite
+Examples of card ID's:
 
-       $ modprobe bttv card=0x71 card=0x87
-
-Here the order of the card id is important and should be the same as that of the
-physical order of the cards. Here card=0x71 represents the Twinhan and clones
-and card=0x87 represents Fusion HDTV5 Lite. These arguments can also be
-specified in decimal, rather than hex:
+Pinnacle PCTV Sat:              94
+Nebula Electronics Digi TV:    104
+pcHDTV HD-2000 TV:             112
+Twinhan DST and clones:                113
+Avermedia AverTV DVB-T 771:    123
+Avermedia AverTV DVB-T 761:    124
+DViCO FusionHDTV DVB-T Lite:   128
+DViCO FusionHDTV 5 Lite:       135
 
+Notice: The order of the card ID should be uprising:
+Example:
        $ modprobe bttv card=113 card=135
+       $ modprobe dvb-bt8xx
 
-Some examples of card-id's
-
-Pinnacle Sat           0x5e  (94)
-Nebula Digi TV         0x68  (104)
-PC HDTV                        0x70  (112)
-Twinhan                        0x71  (113)
-FusionHDTV DVB-T Lite  0x80  (128)
-FusionHDTV5 Lite       0x87  (135)
-
-For a full list of card-id's, see the V4L Documentation within the kernel
-source:  linux/Documentation/video4linux/CARDLIST.bttv
-
-If you have problems with this please do ask on the mailing list.
+For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
+In case of further problems send questions to the mailing list: www.linuxdvb.org.
 
---
 Authors: Richard Walker,
         Jamie Honan,
         Michael Hunold,
         Manu Abraham,
+        Uwe Bugla,
         Michael Krufky
index 75c28a1..bb55f49 100644 (file)
@@ -21,8 +21,9 @@
 use File::Temp qw/ tempdir /;
 use IO::Handle;
 
-@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
-               "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
+@components = ( "sp8870", "sp887x", "tda10045", "tda10046",
+               "tda10046lifeview", "av7110", "dec2000t", "dec2540t",
+               "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
                "or51211", "or51132_qam", "or51132_vsb", "bluebird");
 
 # Check args
@@ -126,6 +127,24 @@ sub tda10046 {
     $outfile;
 }
 
+sub tda10046lifeview {
+    my $sourcefile = "Drv_2.11.02.zip";
+    my $url = "http://www.lifeview.com.tw/drivers/pci_card/FlyDVB-T/$sourcefile";
+    my $hash = "1ea24dee4eea8fe971686981f34fd2e0";
+    my $outfile = "dvb-fe-tda10046.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/LVHybrid.sys", 0x8b088, 24602, "$tmpdir/fwtmp");
+    verify("$tmpdir/fwtmp", $hash);
+    copy("$tmpdir/fwtmp", $outfile);
+
+    $outfile;
+}
+
 sub av7110 {
     my $sourcefile = "dvb-ttpci-01.fw-261d";
     my $url = "http://www.linuxtv.org/downloads/firmware/$sourcefile";
index f5c50b2..0b0380c 100644 (file)
@@ -20,11 +20,23 @@ http://linuxtv.org/downloads/
 
 What's inside this directory:
 
+"avermedia.txt"
+contains detailed information about the
+Avermedia DVB-T cards. See also "bt8xx.txt".
+
+"bt8xx.txt"
+contains detailed information about the
+various bt8xx based "budget" DVB cards.
+
 "cards.txt"
 contains a list of supported hardware.
 
+"ci.txt"
+contains detailed information about the
+CI module as part from TwinHan cards and Clones.
+
 "contributors.txt"
-is the who-is-who of DVB development
+is the who-is-who of DVB development.
 
 "faq.txt"
 contains frequently asked questions and their answers.
@@ -34,19 +46,17 @@ script to download and extract firmware for those devices
 that require it.
 
 "ttusb-dec.txt"
-contains detailed informations about the
+contains detailed information about the
 TT DEC2000/DEC3000 USB DVB hardware.
 
-"bt8xx.txt"
-contains detailed installation instructions for the
-various bt8xx based "budget" DVB cards
-(Nebula, Pinnacle PCTV, Twinhan DST)
-
-"README.dibusb"
-contains detailed information about adapters
-based on DiBcom reference design.
-
 "udev.txt"
 how to get DVB and udev up and running.
 
+"README.dvb-usb"
+contains detailed information about the DVB USB cards.
+
+"README.flexcop"
+contains detailed information about the
+Technisat- and Flexcop B2C2 drivers.
+
 Good luck and have fun!
index 28a31c5..afeaf62 100644 (file)
@@ -196,3 +196,21 @@ Why:       Board specific code doesn't build anymore since ~2.6.0 and no
        users have complained indicating there is no more need for these
        boards.  This should really be considered a last call.
 Who:   Ralf Baechle <ralf@linux-mips.org>
+
+---------------------------
+
+What:  USB driver API moves to EXPORT_SYMBOL_GPL
+When:  Febuary 2008
+Files: include/linux/usb.h, drivers/usb/core/driver.c
+Why:   The USB subsystem has changed a lot over time, and it has been
+       possible to create userspace USB drivers using usbfs/libusb/gadgetfs
+       that operate as fast as the USB bus allows.  Because of this, the USB
+       subsystem will not be allowing closed source kernel drivers to
+       register with it, after this grace period is over.  If anyone needs
+       any help in converting their closed source drivers over to use the
+       userspace filesystems, please contact the
+       linux-usb-devel@lists.sourceforge.net mailing list, and the developers
+       there will be glad to help you out.
+Who:   Greg Kroah-Hartman <gregkh@suse.de>
+
+---------------------------
index 26364d0..f12007b 100644 (file)
@@ -355,6 +355,13 @@ somaxconn - INTEGER
        Defaults to 128.  See also tcp_max_syn_backlog for additional tuning
        for TCP sockets.
 
+tcp_workaround_signed_windows - BOOLEAN
+       If set, assume no receipt of a window scaling option means the
+       remote TCP is broken and treats the window as a signed quantity.
+       If unset, assume the remote TCP is not broken even if we do
+       not receive a window scaling option from them.
+       Default: 0
+
 IP Variables:
 
 ip_local_port_range - 2 INTEGERS
@@ -619,6 +626,11 @@ arp_ignore - INTEGER
        The max value from conf/{all,interface}/arp_ignore is used
        when ARP request is received on the {interface}
 
+arp_accept - BOOLEAN
+       Define behavior when gratuitous arp replies are received:
+       0 - drop gratuitous arp frames
+       1 - accept gratuitous arp frames
+
 app_solicit - INTEGER
        The maximum number of probes to send to the user space ARP daemon
        via netlink before dropping back to multicast probes (see
@@ -717,6 +729,33 @@ accept_ra - BOOLEAN
        Functional default: enabled if local forwarding is disabled.
                            disabled if local forwarding is enabled.
 
+accept_ra_defrtr - BOOLEAN
+       Learn default router in Router Advertisement.
+
+       Functional default: enabled if accept_ra is enabled.
+                           disabled if accept_ra is disabled.
+
+accept_ra_pinfo - BOOLEAN
+       Learn Prefix Inforamtion in Router Advertisement.
+
+       Functional default: enabled if accept_ra is enabled.
+                           disabled if accept_ra is disabled.
+
+accept_ra_rt_info_max_plen - INTEGER
+       Maximum prefix length of Route Information in RA.
+
+       Route Information w/ prefix larger than or equal to this
+       variable shall be ignored.
+
+       Functional default: 0 if accept_ra_rtr_pref is enabled.
+                           -1 if accept_ra_rtr_pref is disabled.
+
+accept_ra_rtr_pref - BOOLEAN
+       Accept Router Preference in RA.
+
+       Functional default: enabled if accept_ra is enabled.
+                           disabled if accept_ra is disabled.
+
 accept_redirects - BOOLEAN
        Accept Redirects.
 
@@ -727,8 +766,8 @@ autoconf - BOOLEAN
        Autoconfigure addresses using Prefix Information in Router 
        Advertisements.
 
-       Functional default: enabled if accept_ra is enabled.
-                           disabled if accept_ra is disabled.
+       Functional default: enabled if accept_ra_pinfo is enabled.
+                           disabled if accept_ra_pinfo is disabled.
 
 dad_transmits - INTEGER
        The amount of Duplicate Address Detection probes to send.
@@ -771,6 +810,12 @@ mtu - INTEGER
        Default Maximum Transfer Unit
        Default: 1280 (IPv6 required minimum)
 
+router_probe_interval - INTEGER
+       Minimum interval (in seconds) between Router Probing described
+       in RFC4191.
+
+       Default: 60
+
 router_solicitation_delay - INTEGER
        Number of seconds to wait after interface is brought up
        before sending Router Solicitations.
index b44dda4..2934028 100644 (file)
@@ -176,6 +176,14 @@ Description:    Force the application to unmap previously mapped buffer memory
                 1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n>
@@ -266,7 +274,7 @@ the V4L2 interface.
 
 
 10. Notes for V4L2 application developers
-========================================
+=========================================
 This driver follows the V4L2 API specifications. In particular, it enforces two
 rules:
 
index c6b7641..b957bea 100644 (file)
@@ -196,6 +196,14 @@ Description:    Force the application to unmap previously mapped buffer memory
                 1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
 Name:           debug
 Type:           ushort
 Syntax:         <n> 
@@ -321,6 +329,7 @@ Vendor ID  Product ID
 ---------  ----------
 0x0c45     0x6001
 0x0c45     0x6005
+0x0c45     0x6007
 0x0c45     0x6009
 0x0c45     0x600d
 0x0c45     0x6024
@@ -370,6 +379,7 @@ HV7131D     Hynix Semiconductor, Inc.
 MI-0343     Micron Technology, Inc.
 OV7630      OmniVision Technologies, Inc.
 PAS106B     PixArt Imaging, Inc.
+PAS202BCA   PixArt Imaging, Inc.
 PAS202BCB   PixArt Imaging, Inc.
 TAS5110C1B  Taiwan Advanced Sensor Corporation
 TAS5130D1B  Taiwan Advanced Sensor Corporation
@@ -493,6 +503,7 @@ Many thanks to following persons for their contribute (listed in alphabetical
 order):
 
 - Luca Capello for the donation of a webcam;
+- Philippe Coval for having helped testing the PAS202BCA image sensor;
 - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
   donation of a webcam;
 - Jon Hollstrom for the donation of a webcam;
diff --git a/Documentation/usb/zc0301.txt b/Documentation/usb/zc0301.txt
new file mode 100644 (file)
index 0000000..f55262c
--- /dev/null
@@ -0,0 +1,254 @@
+
+                    ZC0301 Image Processor and Control Chip
+                                Driver for Linux
+                    =======================================
+
+                               - Documentation -
+
+
+Index
+=====
+1.  Copyright
+2.  Disclaimer
+3.  License
+4.  Overview and features
+5.  Module dependencies
+6.  Module loading
+7.  Module parameters
+8.  Supported devices
+9.  Notes for V4L2 application developers
+10. Contact information
+11. Credits
+
+
+1. Copyright
+============
+Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
+
+
+2. Disclaimer
+=============
+This software is not developed or sponsored by Z-Star Microelectronics Corp.
+Trademarks are property of their respective owner.
+
+
+3. License
+==========
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+4. Overview and features
+========================
+This driver supports the video interface of the devices mounting the ZC0301
+Image Processor and Control Chip.
+
+The driver relies on the Video4Linux2 and USB core modules. It has been
+designed to run properly on SMP systems as well.
+
+The latest version of the ZC0301 driver can be found at the following URL:
+http://www.linux-projects.org/
+
+Some of the features of the driver are:
+
+- full compliance with the Video4Linux2 API (see also "Notes for V4L2
+  application developers" paragraph);
+- available mmap or read/poll methods for video streaming through isochronous
+  data transfers;
+- automatic detection of image sensor;
+- video format is standard JPEG;
+- dynamic driver control thanks to various module parameters (see "Module
+  parameters" paragraph);
+- up to 64 cameras can be handled at the same time; they can be connected and
+  disconnected from the host many times without turning off the computer, if
+  the system supports hotplugging;
+
+
+5. Module dependencies
+======================
+For it to work properly, the driver needs kernel support for Video4Linux and
+USB.
+
+The following options of the kernel configuration file must be enabled and
+corresponding modules must be compiled:
+
+       # Multimedia devices
+       #
+       CONFIG_VIDEO_DEV=m
+
+       # USB support
+       #
+       CONFIG_USB=m
+
+In addition, depending on the hardware being used, the modules below are
+necessary:
+
+       # USB Host Controller Drivers
+       #
+       CONFIG_USB_EHCI_HCD=m
+       CONFIG_USB_UHCI_HCD=m
+       CONFIG_USB_OHCI_HCD=m
+
+The ZC0301 controller also provides a built-in microphone interface. It is
+supported by the USB Audio driver thanks to the ALSA API:
+
+       # Sound
+       #
+       CONFIG_SOUND=y
+
+       # Advanced Linux Sound Architecture
+       #
+       CONFIG_SND=m
+
+       # USB devices
+       #
+       CONFIG_SND_USB_AUDIO=m
+
+And finally:
+
+       # USB Multimedia devices
+       #
+       CONFIG_USB_ZC0301=m
+
+
+6. Module loading
+=================
+To use the driver, it is necessary to load the "zc0301" module into memory
+after every other module required: "videodev", "usbcore" and, depending on
+the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
+
+Loading can be done as shown below:
+
+       [root@localhost home]# modprobe zc0301
+
+At this point the devices should be recognized. You can invoke "dmesg" to
+analyze kernel messages and verify that the loading process has gone well:
+
+       [user@localhost home]$ dmesg
+
+
+7. Module parameters
+====================
+Module parameters are listed below:
+-------------------------------------------------------------------------------
+Name:           video_nr
+Type:           short array (min = 0, max = 64)
+Syntax:         <-1|n[,...]>
+Description:    Specify V4L2 minor mode number:
+                -1 = use next available
+                 n = use minor number n
+                You can specify up to 64 cameras this way.
+                For example:
+                video_nr=-1,2,-1 would assign minor number 2 to the second
+                registered camera and use auto for the first one and for every
+                other camera.
+Default:        -1
+-------------------------------------------------------------------------------
+Name:           force_munmap
+Type:           bool array (min = 0, max = 64)
+Syntax:         <0|1[,...]>
+Description:    Force the application to unmap previously mapped buffer memory
+                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+                all the applications support this feature. This parameter is
+                specific for each detected camera.
+                0 = do not force memory unmapping
+                1 = force memory unmapping (save memory)
+Default:        0
+-------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
+Name:           debug
+Type:           ushort
+Syntax:         <n>
+Description:    Debugging information level, from 0 to 3:
+                0 = none (use carefully)
+                1 = critical errors
+                2 = significant informations
+                3 = more verbose messages
+                Level 3 is useful for testing only, when only one device
+                is used at the same time. It also shows some more informations
+                about the hardware being detected. This module parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
+
+
+8. Supported devices
+====================
+None of the names of the companies as well as their products will be mentioned
+here. They have never collaborated with the author, so no advertising.
+
+From the point of view of a driver, what unambiguously identify a device are
+its vendor and product USB identifiers. Below is a list of known identifiers of
+devices mounting the ZC0301 Image Processor and Control Chips:
+
+Vendor ID  Product ID
+---------  ----------
+0x041e     0x4017
+0x041e     0x401c
+0x041e     0x401e
+0x041e     0x4034
+0x041e     0x4035
+0x046d     0x08ae
+0x0ac8     0x0301
+0x10fd     0x8050
+
+The list above does not imply that all those devices work with this driver: up
+until now only the ones that mount the following image sensors are supported;
+kernel messages will always tell you whether this is the case:
+
+Model       Manufacturer
+-----       ------------
+PAS202BCB   PixArt Imaging, Inc.
+
+
+9. Notes for V4L2 application developers
+========================================
+This driver follows the V4L2 API specifications. In particular, it enforces two
+rules:
+
+- exactly one I/O method, either "mmap" or "read", is associated with each
+file descriptor. Once it is selected, the application must close and reopen the
+device to switch to the other I/O method;
+
+- although it is not mandatory, previously mapped buffer memory should always
+be unmapped before calling any "VIDIOC_S_CROP" or "VIDIOC_S_FMT" ioctl's.
+The same number of buffers as before will be allocated again to match the size
+of the new video frames, so you have to map the buffers again before any I/O
+attempts on them.
+
+
+10. Contact information
+=======================
+The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
+
+GPG/PGP encrypted e-mail's are accepted. The GPG key ID of the author is
+'FCE635A4'; the public 1024-bit key should be available at any keyserver;
+the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
+
+
+11. Credits
+===========
+- Informations about the chip internals needed to enable the I2C protocol have
+  been taken from the documentation of the ZC030x Video4Linux1 driver written
+  by Andrew Birkett <andy@nobugs.org>;
+- The initialization values of the ZC0301 controller connected to the PAS202BCB
+  image sensor have been taken from the SPCA5XX driver maintained by
+  Michel Xhaard <mxhaard@magic.fr>.
index 8bea3fb..3b39a91 100644 (file)
@@ -43,3 +43,5 @@
  42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025]
  43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1]
  44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50,18ac:db54]
+ 45 -> KWorld HardwareMpegTV XPert                         [17de:0840]
+ 46 -> DViCO FusionHDTV DVB-T Hybrid                       [18ac:db40,18ac:db44]
index a0c7cad..a302668 100644 (file)
@@ -8,3 +8,4 @@
   7 -> Leadtek Winfast USB II                   (em2800)
   8 -> Kworld USB2800                           (em2800)
   9 -> Pinnacle Dazzle DVC 90                   (em2820/em2840) [2304:0207]
+ 12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
index da4fb89..8c71954 100644 (file)
  82 -> MSI TV@Anywhere plus                     [1462:6231]
  83 -> Terratec Cinergy 250 PCI TV              [153b:1160]
  84 -> LifeView FlyDVB Trio                     [5168:0319]
+ 85 -> AverTV DVB-T 777                         [1461:2c05]
+ 86 -> LifeView FlyDVB-T                        [5168:0301]
+ 87 -> ADS Instant TV Duo Cardbus PTV331        [0331:1421]
+ 88 -> Tevion/KWorld DVB-T 220RF                [17de:7201]
+ 89 -> ELSA EX-VISION 700TV                     [1048:226c]
+ 90 -> Kworld ATSC110                           [17de:7350]
+ 91 -> AVerMedia A169 B                         [1461:7360]
+ 92 -> AVerMedia A169 B1                        [1461:6360]
+ 93 -> Medion 7134 Bridge #2                    [16be:0005]
index f6d0cf7..1bcdac6 100644 (file)
@@ -64,8 +64,10 @@ tuner=62 - Philips TEA5767HN FM Radio
 tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
 tuner=64 - LG TDVS-H062F/TUA6034
 tuner=65 - Ymec TVF66T5-B/DFF
-tuner=66 - LG NTSC (TALN mini series)
+tuner=66 - LG TALN series
 tuner=67 - Philips TD1316 Hybrid Tuner
 tuner=68 - Philips TUV1236D ATSC/NTSC dual in
-tuner=69 - Tena TNF 5335 MF
+tuner=69 - Tena TNF 5335 and similar models
 tuner=70 - Samsung TCPN 2121P30A
+tuner=71 - Xceive xc3028
+tuner=72 - Thomson FE6600
diff --git a/Documentation/video4linux/README.cpia2 b/Documentation/video4linux/README.cpia2
new file mode 100644 (file)
index 0000000..ce8213d
--- /dev/null
@@ -0,0 +1,130 @@
+$Id: README,v 1.7 2005/08/29 23:39:57 sbertin Exp $
+
+1. Introduction
+
+       This is a driver for STMicroelectronics's CPiA2 (second generation
+Colour Processor Interface ASIC) based cameras. This camera outputs an MJPEG
+stream at up to vga size. It implements the Video4Linux interface as much as
+possible.  Since the V4L interface does not support compressed formats, only
+an mjpeg enabled application can be used with the camera. We have modified the
+gqcam application to view this stream.
+
+       The driver is implemented as two kernel modules. The cpia2 module
+contains the camera functions and the V4L interface.  The cpia2_usb module
+contains usb specific functions.  The main reason for this was the size of the
+module was getting out of hand, so I separted them.  It is not likely that
+there will be a parallel port version.
+
+FEATURES:
+   - Supports cameras with the Vision stv6410 (CIF) and stv6500 (VGA) cmos
+     sensors. I only have the vga sensor, so can't test the other.
+   - Image formats: VGA, QVGA, CIF, QCIF, and a number of sizes in between.
+     VGA and QVGA are the native image sizes for the VGA camera. CIF is done
+     in the coprocessor by scaling QVGA.  All other sizes are done by clipping.
+   - Palette: YCrCb, compressed with MJPEG.
+   - Some compression parameters are settable.
+   - Sensor framerate is adjustable (up to 30 fps CIF, 15 fps VGA).
+   - Adjust brightness, color, contrast while streaming.
+   - Flicker control settable for 50 or 60 Hz mains frequency.
+
+2. Making and installing the stv672 driver modules:
+
+       Requirements:
+       -------------
+       This should work with 2.4 (2.4.23 and later) and 2.6 kernels, but has
+only been tested on 2.6.  Video4Linux must be either compiled into the kernel or
+available as a module.  Video4Linux2 is automatically detected and made
+available at compile time.
+
+       Compiling:
+       ----------
+       As root, do a make install.  This will compile and install the modules
+into the media/video directory in the module tree. For 2.4 kernels, use
+Makefile_2.4 (aka do make -f Makefile_2.4 install).
+
+       Setup:
+       ------
+       Use 'modprobe cpia2' to load and 'modprobe -r cpia2' to unload. This
+may be done automatically by your distribution.
+
+3. Driver options
+
+       Option          Description
+       ------          -----------
+       video_nr        video device to register (0=/dev/video0, etc)
+                       range -1 to 64.  default is -1 (first available)
+                       If you have more than 1 camera, this MUST be -1.
+       buffer_size     Size for each frame buffer in bytes (default 68k)
+       num_buffers     Number of frame buffers (1-32, default 3)
+       alternate       USB Alternate (2-7, default 7)
+       flicker_freq    Frequency for flicker reduction(50 or 60, default 60)
+       flicker_mode    0 to disable, or 1 to enable flicker reduction.
+                       (default 0). This is only effective if the camera
+                       uses a stv0672 coprocessor.
+
+       Setting the options:
+       --------------------
+       If you are using modules, edit /etc/modules.conf and add an options
+line like this:
+       options cpia2 num_buffers=3 buffer_size=65535
+
+       If the driver is compiled into the kernel, at boot time specify them
+like this:
+       cpia2.num_buffers=3 cpia2.buffer_size=65535
+
+       What buffer size should I use?
+       ------------------------------
+       The maximum image size depends on the alternate you choose, and the
+frame rate achieved by the camera.  If the compression engine is able to
+keep up with the frame rate, the maximum image size is given by the table
+below.
+       The compression engine starts out at maximum compression, and will
+increase image quality until it is close to the size in the table.  As long
+as the compression engine can keep up with the frame rate, after a short time
+the images will all be about the size in the table, regardless of resolution.
+       At low alternate settings, the compression engine may not be able to
+compress the image enough and will reduce the frame rate by producing larger
+images.
+       The default of 68k should be good for most users.  This will handle
+any alternate at frame rates down to 15fps.  For lower frame rates, it may
+be necessary to increase the buffer size to avoid having frames dropped due
+to insufficient space.
+
+                            Image size(bytes)
+       Alternate  bytes/ms   15fps    30fps
+           2         128      8533     4267
+           3         384     25600    12800
+           4         640     42667    21333
+           5         768     51200    25600
+           6         896     59733    29867
+           7        1023     68200    34100
+
+       How many buffers should I use?
+       ------------------------------
+       For normal streaming, 3 should give the best results.  With only 2,
+it is possible for the camera to finish sending one image just after a
+program has started reading the other.  If this happens, the driver must drop
+a frame.  The exception to this is if you have a heavily loaded machine.  In
+this case use 2 buffers.  You are probably not reading at the full frame rate.
+If the camera can send multiple images before a read finishes, it could
+overwrite the third buffer before the read finishes, leading to a corrupt
+image.  Single and double buffering have extra checks to avoid overwriting.
+
+4. Using the camera
+
+       We are providing a modified gqcam application to view the output. In
+order to avoid confusion, here it is called mview.  There is also the qx5view
+program which can also control the lights on the qx5 microscope. MJPEG Tools
+(http://mjpeg.sourceforge.net) can also be used to record from the camera.
+
+5. Notes to developers:
+
+   - This is a driver version stripped of the 2.4 back compatibility
+     and old MJPEG ioctl API. See cpia2.sf.net for 2.4 support.
+
+6. Thanks:
+
+   - Peter Pregler <Peter_Pregler@email.com>,
+     Scott J. Bertin <scottbertin@yahoo.com>, and
+     Jarl Totland <Jarl.Totland@bdc.no> for the original cpia driver, which
+     this one was modelled from.
diff --git a/Documentation/video4linux/cpia2_overview.txt b/Documentation/video4linux/cpia2_overview.txt
new file mode 100644 (file)
index 0000000..a6e5366
--- /dev/null
@@ -0,0 +1,38 @@
+                       Programmer's View of Cpia2
+
+Cpia2 is the second generation video coprocessor from VLSI Vision Ltd (now a
+division of ST Microelectronics).  There are two versions.  The first is the
+STV0672, which is capable of up to 30 frames per second (fps) in frame sizes
+up to CIF, and 15 fps for VGA frames.  The STV0676 is an improved version,
+which can handle up to 30 fps VGA.  Both coprocessors can be attached to two
+CMOS sensors - the vvl6410 CIF sensor and the vvl6500 VGA sensor.  These will
+be referred to as the 410 and the 500 sensors, or the CIF and VGA sensors.
+
+The two chipsets operate almost identically.  The core is an 8051 processor,
+running two different versions of firmware.  The 672 runs the VP4 video
+processor code, the 676 runs VP5.  There are a few differences in register
+mappings for the two chips.  In these cases, the symbols defined in the
+header files are marked with VP4 or VP5 as part of the symbol name.
+
+The cameras appear externally as three sets of registers. Setting register
+values is the only way to control the camera.  Some settings are
+interdependant, such as the sequence required to power up the camera. I will
+try to make note of all of these cases.
+
+The register sets are called blocks.  Block 0 is the system block.  This
+section is always powered on when the camera is plugged in.  It contains
+registers that control housekeeping functions such as powering up the video
+processor.  The video processor is the VP block.  These registers control
+how the video from the sensor is processed.  Examples are timing registers,
+user mode (vga, qvga), scaling, cropping, framerates, and so on.  The last
+block is the video compressor (VC).  The video stream sent from the camera is
+compressed as Motion JPEG (JPEGA).  The VC controls all of the compression
+parameters.  Looking at the file cpia2_registers.h, you can get a full view
+of these registers and the possible values for most of them.
+
+One or more registers can be set or read by sending a usb control message to
+the camera.  There are three modes for this.  Block mode requests a number
+of contiguous registers.  Random mode reads or writes random registers with
+a tuple structure containing address/value pairs.  The repeat mode is only
+used by VP4 to load a firmware patch.  It contains a starting address and
+a sequence of bytes to be written into a gpio port.
\ No newline at end of file
index 8db5c33..7a1cbda 100644 (file)
@@ -1524,12 +1524,6 @@ M:       davem@davemloft.net
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
-LANMEDIA WAN CARD DRIVER
-P:     Andrew Stanley-Jones
-M:     asj@lanmedia.com
-W:     http://www.lanmedia.com/
-S:     Supported
 LAPB module
 P:     Henner Eisen
 M:     eis@baty.hanse.de
@@ -2902,6 +2896,14 @@ L:       video4linux-list@redhat.com
 W:     http://www.linux-projects.org
 S:     Maintained
 
+USB ZC0301 DRIVER
+P:     Luca Risolia
+M:     luca.risolia@studio.unibo.it
+L:     linux-usb-devel@lists.sourceforge.net
+L:     video4linux-list@redhat.com
+W:     http://www.linux-projects.org
+S:     Maintained
+
 USB ZD1201 DRIVER
 P:     Jeroen Vreeken
 M:     pe1rxq@amsat.org
diff --git a/README b/README
index 0d318ab..05e0555 100644 (file)
--- a/README
+++ b/README
@@ -74,7 +74,7 @@ INSTALLING the kernel:
    whatever the kernel-du-jour happens to be.
 
  - You can also upgrade between 2.6.xx releases by patching.  Patches are
-   distributed in the traditional gzip and the new bzip2 format.  To
+   distributed in the traditional gzip and the newer bzip2 format.  To
    install by patching, get all the newer patch files, enter the
    top level directory of the kernel source (linux-2.6.xx) and execute:
 
index d31b1cb..2360940 100644 (file)
@@ -788,6 +788,8 @@ static int locomo_probe(struct platform_device *dev)
        if (!mem)
                return -EINVAL;
        irq = platform_get_irq(dev, 0);
+       if (irq < 0)
+               return -ENXIO;
 
        return __locomo_probe(&dev->dev, mem, irq);
 }
index 1475089..93352f6 100644 (file)
@@ -943,6 +943,8 @@ static int sa1111_probe(struct platform_device *pdev)
        if (!mem)
                return -EINVAL;
        irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return -ENXIO;
 
        return __sa1111_probe(&pdev->dev, mem, irq);
 }
index 4303d98..d13270c 100644 (file)
@@ -202,11 +202,6 @@ struct clk realview_clcd_clk = {
 /*
  * CLCD support.
  */
-#define SYS_CLCD_MODE_MASK     (3 << 0)
-#define SYS_CLCD_MODE_888      (0 << 0)
-#define SYS_CLCD_MODE_5551     (1 << 0)
-#define SYS_CLCD_MODE_565_RLSB (2 << 0)
-#define SYS_CLCD_MODE_565_BLSB (3 << 0)
 #define SYS_CLCD_NLCDIOON      (1 << 2)
 #define SYS_CLCD_VDDPOSSWITCH  (1 << 3)
 #define SYS_CLCD_PWR3V5SWITCH  (1 << 4)
@@ -360,29 +355,10 @@ static void realview_clcd_enable(struct clcd_fb *fb)
        void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
        u32 val;
 
-       val = readl(sys_clcd);
-       val &= ~SYS_CLCD_MODE_MASK;
-
-       switch (fb->fb.var.green.length) {
-       case 5:
-               val |= SYS_CLCD_MODE_5551;
-               break;
-       case 6:
-               val |= SYS_CLCD_MODE_565_RLSB;
-               break;
-       case 8:
-               val |= SYS_CLCD_MODE_888;
-               break;
-       }
-
-       /*
-        * Set the MUX
-        */
-       writel(val, sys_clcd);
-
        /*
-        * And now enable the PSUs
+        * Enable the PSUs
         */
+       val = readl(sys_clcd);
        val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH;
        writel(val, sys_clcd);
 }
index 3cbe6e9..1629c3a 100644 (file)
@@ -1,49 +1,87 @@
 #
 # Automatically generated make config: don't edit
 #
+CONFIG_X86_32=y
+CONFIG_SEMAPHORE_SLEEPERS=y
 CONFIG_X86=y
 CONFIG_MMU=y
-CONFIG_UID16=y
 CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_DMI=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-CONFIG_AUDIT=y
-CONFIG_AUDITSYSCALL=y
-CONFIG_LOG_BUF_SHIFT=15
-CONFIG_HOTPLUG=y
-# CONFIG_IKCONFIG is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_VM86=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
 
 #
 # Processor type and features
@@ -66,43 +104,50 @@ CONFIG_X86_PC=y
 # CONFIG_MPENTIUMII is not set
 # CONFIG_MPENTIUMIII is not set
 # CONFIG_MPENTIUMM is not set
-CONFIG_MPENTIUM4=y
+# CONFIG_MPENTIUM4 is not set
 # CONFIG_MK6 is not set
-# CONFIG_MK7 is not set
+CONFIG_MK7=y
 # CONFIG_MK8 is not set
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
 # CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
 # CONFIG_MCYRIXIII is not set
 # CONFIG_MVIAC3_2 is not set
 # CONFIG_X86_GENERIC is not set
 CONFIG_X86_CMPXCHG=y
 CONFIG_X86_XADD=y
-CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_L1_CACHE_SHIFT=6
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
+CONFIG_X86_CMPXCHG64=y
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_INTEL_USERCOPY=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_USE_3DNOW=y
+CONFIG_X86_TSC=y
 # CONFIG_HPET_TIMER is not set
-# CONFIG_HPET_EMULATE_RTC is not set
-CONFIG_SMP=y
-CONFIG_NR_CPUS=8
-CONFIG_SCHED_SMT=y
-CONFIG_PREEMPT=y
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_X86_UP_APIC=y
+CONFIG_X86_UP_IOAPIC=y
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_X86_IO_APIC=y
-CONFIG_X86_TSC=y
 CONFIG_X86_MCE=y
 CONFIG_X86_MCE_NONFATAL=y
-CONFIG_X86_MCE_P4THERMAL=y
+# CONFIG_X86_MCE_P4THERMAL is not set
 # CONFIG_TOSHIBA is not set
 # CONFIG_I8K is not set
+# CONFIG_X86_REBOOTFIXUPS is not set
 # CONFIG_MICROCODE is not set
 # CONFIG_X86_MSR is not set
 # CONFIG_X86_CPUID is not set
@@ -111,41 +156,71 @@ CONFIG_X86_MCE_P4THERMAL=y
 # Firmware Drivers
 #
 # CONFIG_EDD is not set
+# CONFIG_DELL_RBU is not set
+# CONFIG_DCDBAS is not set
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
 # CONFIG_HIGHMEM64G is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_3G_OPT is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
 # CONFIG_EFI is not set
-CONFIG_IRQBALANCE=y
-CONFIG_HAVE_DEC_LOCK=y
-# CONFIG_REGPARM is not set
+CONFIG_REGPARM=y
+# CONFIG_SECCOMP is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_KEXEC is not set
+CONFIG_PHYSICAL_START=0x100000
+CONFIG_DOUBLEFAULT=y
 
 #
 # Power management options (ACPI, APM)
 #
 CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
 CONFIG_SOFTWARE_SUSPEND=y
+CONFIG_PM_STD_PARTITION="/dev/hda2"
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
 #
 CONFIG_ACPI=y
-CONFIG_ACPI_SLEEP=y
-CONFIG_ACPI_SLEEP_PROC_FS=y
-CONFIG_ACPI_AC=y
-CONFIG_ACPI_BATTERY=y
-CONFIG_ACPI_BUTTON=y
-CONFIG_ACPI_FAN=y
-CONFIG_ACPI_PROCESSOR=y
-CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_SLEEP is not set
+# CONFIG_ACPI_AC is not set
+# CONFIG_ACPI_BATTERY is not set
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_VIDEO is not set
+# CONFIG_ACPI_HOTKEY is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
 # CONFIG_ACPI_ASUS is not set
+# CONFIG_ACPI_IBM is not set
 # CONFIG_ACPI_TOSHIBA is not set
+CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_EC=y
 CONFIG_ACPI_POWER=y
 CONFIG_ACPI_SYSTEM=y
 # CONFIG_X86_PM_TIMER is not set
+# CONFIG_ACPI_CONTAINER is not set
 
 #
 # APM (Advanced Power Management) BIOS Support
@@ -168,19 +243,18 @@ CONFIG_PCI_GOANY=y
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
-# CONFIG_PCI_USE_VECTOR is not set
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-CONFIG_ISA=y
-# CONFIG_EISA is not set
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_ISA_DMA_API=y
+# CONFIG_ISA is not set
 # CONFIG_MCA is not set
 # CONFIG_SCx200 is not set
 
 #
-# PCMCIA/CardBus support
+# PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_PCMCIA is not set
-CONFIG_PCMCIA_PROBE=y
+# CONFIG_PCCARD is not set
 
 #
 # PCI Hotplug Support
@@ -191,8 +265,147 @@ CONFIG_PCMCIA_PROBE=y
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_MISC=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+# CONFIG_IP_NF_IRC is not set
+# CONFIG_IP_NF_NETBIOS_NS is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_PPTP is not set
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+# CONFIG_IP_NF_MATCH_MULTIPORT is not set
+# CONFIG_IP_NF_MATCH_TOS is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+# CONFIG_IP_NF_MATCH_AH_ESP is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_FILTER=y
+# CONFIG_IP_NF_TARGET_REJECT is not set
+CONFIG_IP_NF_TARGET_LOG=y
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_IP_NF_TARGET_TCPMSS is not set
+# CONFIG_IP_NF_NAT is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
 
 #
 # Device Drivers
@@ -201,7 +414,14 @@ CONFIG_BINFMT_MISC=y
 #
 # Generic Driver Options
 #
-CONFIG_FW_LOADER=m
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -213,40 +433,36 @@ CONFIG_FW_LOADER=m
 #
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
-CONFIG_PARPORT_PC_CML1=y
 # CONFIG_PARPORT_SERIAL is not set
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_OTHER is not set
-# CONFIG_PARPORT_1284 is not set
+# CONFIG_PARPORT_GSC is not set
+CONFIG_PARPORT_1284=y
 
 #
 # Plug and Play support
 #
-CONFIG_PNP=y
-# CONFIG_PNP_DEBUG is not set
-
-#
-# Protocols
-#
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
+# CONFIG_PNP is not set
 
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
-# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_FD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
-CONFIG_LBD=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -257,34 +473,31 @@ CONFIG_BLK_DEV_IDE=y
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
+# CONFIG_BLK_DEV_IDE_SATA is not set
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_TASKFILE_IO=y
 
 #
 # IDE chipset support/bugfixes
 #
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_CMD640=y
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_BLK_DEV_CMD640 is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_RZ1000=y
+# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
@@ -294,10 +507,12 @@ CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5520 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_CS5535 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_SC1200 is not set
-CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_BLK_DEV_PDC202XX_NEW is not set
@@ -306,9 +521,8 @@ CONFIG_BLK_DEV_PIIX=y
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
 # CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
@@ -317,8 +531,9 @@ CONFIG_IDEDMA_AUTO=y
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
+# CONFIG_SCSI_PROC_FS is not set
 
 #
 # SCSI support type (disk, tape, CD-ROM)
@@ -327,7 +542,8 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
 # CONFIG_BLK_DEV_SR is not set
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -341,79 +557,47 @@ CONFIG_CHR_DEV_SG=y
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
 
 #
 # SCSI low-level drivers
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
-CONFIG_SCSI_DPT_I2O=m
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_MEGARAID is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_SVW is not set
-CONFIG_SCSI_ATA_PIIX=y
-# CONFIG_SCSI_SATA_PROMISE is not set
-CONFIG_SCSI_SATA_SX4=m
-# CONFIG_SCSI_SATA_SIL is not set
-CONFIG_SCSI_SATA_SIS=m
-# CONFIG_SCSI_SATA_VIA is not set
-# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 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_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
 # CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_IMM is not set
-# CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_IPR=m
-# CONFIG_SCSI_IPR_TRACE is not set
-# CONFIG_SCSI_IPR_DUMP is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA6322 is not set
-# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
@@ -422,37 +606,14 @@ CONFIG_SCSI_QLA2XXX=y
 # Fusion MPT device support
 #
 # CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
-CONFIG_IEEE1394=y
-
-#
-# Subsystem Options
-#
-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_OUI_DB is not set
-# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
-
-#
-# Device Drivers
-#
-
-#
-# Texas Instruments PCILynx requires I2C
-#
-CONFIG_IEEE1394_OHCI1394=y
-
-#
-# Protocol Drivers
-#
-# CONFIG_IEEE1394_VIDEO1394 is not set
-# CONFIG_IEEE1394_SBP2 is not set
-# CONFIG_IEEE1394_ETH1394 is not set
-# CONFIG_IEEE1394_DV1394 is not set
-CONFIG_IEEE1394_RAWIO=y
-# CONFIG_IEEE1394_CMP is not set
+# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -460,130 +621,13 @@ CONFIG_IEEE1394_RAWIO=y
 # CONFIG_I2O is not set
 
 #
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-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
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
+# Network device support
 #
-CONFIG_IP_NF_CONNTRACK=y
-# CONFIG_IP_NF_FTP is not set
-# CONFIG_IP_NF_IRC is not set
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-CONFIG_IP_NF_QUEUE=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MATCH_LIMIT=y
-CONFIG_IP_NF_MATCH_IPRANGE=y
-CONFIG_IP_NF_MATCH_MAC=y
-CONFIG_IP_NF_MATCH_PKTTYPE=y
-CONFIG_IP_NF_MATCH_MARK=y
-CONFIG_IP_NF_MATCH_MULTIPORT=y
-CONFIG_IP_NF_MATCH_TOS=y
-CONFIG_IP_NF_MATCH_RECENT=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_DSCP=y
-CONFIG_IP_NF_MATCH_AH_ESP=y
-CONFIG_IP_NF_MATCH_LENGTH=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_MATCH_TCPMSS=y
-CONFIG_IP_NF_MATCH_HELPER=y
-CONFIG_IP_NF_MATCH_STATE=y
-CONFIG_IP_NF_MATCH_CONNTRACK=y
-CONFIG_IP_NF_MATCH_OWNER=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_NAT=y
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_SAME=y
-# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_TARGET_TOS=y
-CONFIG_IP_NF_TARGET_ECN=y
-CONFIG_IP_NF_TARGET_DSCP=y
-CONFIG_IP_NF_TARGET_MARK=y
-CONFIG_IP_NF_TARGET_CLASSIFY=y
-CONFIG_IP_NF_TARGET_LOG=y
-CONFIG_IP_NF_TARGET_ULOG=y
-CONFIG_IP_NF_TARGET_TCPMSS=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_IP_NF_TARGET_NOTRACK=m
-CONFIG_IP_NF_RAW=m
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
+# CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_NET_SB1000 is not set
 
 #
 # ARCnet devices
@@ -591,46 +635,39 @@ CONFIG_DUMMY=m
 # CONFIG_ARCNET is not set
 
 #
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
 
 #
 # Tulip family network device support
 #
 # CONFIG_NET_TULIP is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
 # CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_CS89x0 is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
+CONFIG_E100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
 # CONFIG_8139CP is not set
-CONFIG_8139TOO=y
-CONFIG_8139TOO_PIO=y
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_8139TOO is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -644,21 +681,24 @@ CONFIG_8139TOO_PIO=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
-# CONFIG_E1000_NAPI is not set
-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
+# CONFIG_CHELSIO_T1 is not set
 # CONFIG_IXGB is not set
-CONFIG_S2IO=m
-# CONFIG_S2IO_NAPI is not set
+# CONFIG_S2IO is not set
 
 #
 # Token Ring devices
@@ -682,6 +722,8 @@ CONFIG_S2IO=m
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -703,26 +745,14 @@ CONFIG_INPUT=y
 #
 CONFIG_INPUT_MOUSEDEV=y
 CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1280
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1024
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
+CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -734,15 +764,25 @@ CONFIG_KEYBOARD_ATKBD=y
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 # CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
 # Character devices
 #
 CONFIG_VT=y
@@ -757,12 +797,14 @@ CONFIG_SERIAL_8250=y
 # CONFIG_SERIAL_8250_CONSOLE is not set
 # CONFIG_SERIAL_8250_ACPI is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -770,7 +812,6 @@ CONFIG_PRINTER=y
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
 # CONFIG_TIPAR is not set
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -782,9 +823,8 @@ CONFIG_PRINTER=y
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
+CONFIG_NVRAM=y
+CONFIG_RTC=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -793,34 +833,149 @@ CONFIG_PRINTER=y
 #
 # Ftape, the floppy tape device driver
 #
+# CONFIG_FTAPE is not set
 CONFIG_AGP=y
 # CONFIG_AGP_ALI is not set
 # CONFIG_AGP_ATI is not set
 # CONFIG_AGP_AMD is not set
 # CONFIG_AGP_AMD64 is not set
-CONFIG_AGP_INTEL=y
+# CONFIG_AGP_INTEL is not set
 # CONFIG_AGP_NVIDIA is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_SWORKS is not set
-# CONFIG_AGP_VIA is not set
+CONFIG_AGP_VIA=y
 # CONFIG_AGP_EFFICEON is not set
 CONFIG_DRM=y
 # CONFIG_DRM_TDFX is not set
-# CONFIG_DRM_GAMMA is not set
 # CONFIG_DRM_R128 is not set
-# CONFIG_DRM_RADEON is not set
-# CONFIG_DRM_I810 is not set
-CONFIG_DRM_I830=y
+CONFIG_DRM_RADEON=y
 # CONFIG_DRM_MGA is not set
 # CONFIG_DRM_SIS is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
 # CONFIG_MWAVE is not set
+# CONFIG_CS5535_GPIO is not set
 # CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
 # CONFIG_HANGCHECK_TIMER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
 # I2C support
 #
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_ISA=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+CONFIG_I2C_VIAPRO=y
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+CONFIG_SENSORS_IT87=y
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
 # Misc devices
@@ -828,27 +983,118 @@ CONFIG_DRM_I830=y
 # CONFIG_IBM_ASM is not set
 
 #
+# Multimedia Capabilities Port drivers
+#
+
+#
 # Multimedia devices
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+CONFIG_VIDEO_SAA7134=y
+# CONFIG_VIDEO_SAA7134_ALSA is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_DPC is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_VIDEO_AUDIO_DECODER is not set
+# CONFIG_VIDEO_DECODER is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
 
 #
 # Digital Video Broadcasting Devices
 #
 # CONFIG_DVB is not set
+CONFIG_VIDEO_TUNER=y
+CONFIG_VIDEO_BUF=y
+CONFIG_VIDEO_IR=y
 
 #
 # Graphics support
 #
-# CONFIG_FB is not set
-# CONFIG_VIDEO_SELECT is not set
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VESA is not set
+CONFIG_VIDEO_SELECT=y
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_I810 is not set
+# CONFIG_FB_INTEL is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_DEBUG is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_CYBLA is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_VIRTUAL is not set
 
 #
 # Console display driver support
 #
 CONFIG_VGA_CONSOLE=y
-# CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -864,10 +1110,13 @@ CONFIG_SND_PCM=y
 CONFIG_SND_RAWMIDI=y
 CONFIG_SND_SEQUENCER=y
 # CONFIG_SND_SEQ_DUMMY is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_RTCTIMER=y
+CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
@@ -875,6 +1124,8 @@ CONFIG_SND_SEQUENCER_OSS=y
 # Generic devices
 #
 CONFIG_SND_MPU401_UART=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_AC97_BUS=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
@@ -882,74 +1133,57 @@ CONFIG_SND_MPU401_UART=y
 # CONFIG_SND_MPU401 is not set
 
 #
-# ISA devices
-#
-# CONFIG_SND_AD1848 is not set
-# CONFIG_SND_CS4231 is not set
-# CONFIG_SND_CS4232 is not set
-# CONFIG_SND_CS4236 is not set
-# CONFIG_SND_ES1688 is not set
-# CONFIG_SND_ES18XX is not set
-# CONFIG_SND_GUSCLASSIC is not set
-# CONFIG_SND_GUSEXTREME is not set
-# CONFIG_SND_GUSMAX is not set
-# CONFIG_SND_INTERWAVE is not set
-# CONFIG_SND_INTERWAVE_STB is not set
-# CONFIG_SND_OPTI92X_AD1848 is not set
-# CONFIG_SND_OPTI92X_CS4231 is not set
-# CONFIG_SND_OPTI93X is not set
-# CONFIG_SND_SB8 is not set
-# CONFIG_SND_SB16 is not set
-# CONFIG_SND_SBAWE is not set
-# CONFIG_SND_WAVEFRONT is not set
-# CONFIG_SND_CMI8330 is not set
-# CONFIG_SND_OPL3SA2 is not set
-# CONFIG_SND_SGALAXY is not set
-# CONFIG_SND_SSCAPE is not set
-
-#
 # PCI devices
 #
-CONFIG_SND_AC97_CODEC=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS4000 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
 # CONFIG_SND_AU8810 is not set
 # CONFIG_SND_AU8820 is not set
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5535AUDIO is not set
 # CONFIG_SND_EMU10K1 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_ALS4000 is not set
-# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_EMU10K1X is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
-CONFIG_SND_INTEL8X0=y
+# CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
-# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_TRIDENT is not set
+CONFIG_SND_VIA82XX=y
+# CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
 
 #
-# ALSA USB devices
+# USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
 
 #
 # Open Sound System
@@ -959,6 +1193,8 @@ CONFIG_SND_INTEL8X0=y
 #
 # USB support
 #
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
@@ -968,6 +1204,8 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
 
 #
 # USB Host Controller Drivers
@@ -975,68 +1213,93 @@ CONFIG_USB_DEVICEFS=y
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_UHCI_HCD=y
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
 #
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH_TTY is not set
-# CONFIG_USB_MIDI is not set
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 # CONFIG_USB_ACM is not set
-CONFIG_USB_PRINTER=y
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
 # CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
-# USB Human Interface Devices (HID)
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
 #
-CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
 # CONFIG_USB_MTOUCH is not set
-CONFIG_USB_EGALAX=m
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
 
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
 # USB Multimedia devices
 #
 # CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_PWC is not set
 
 #
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
+# USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
+# CONFIG_USB_MON is not set
 
 #
 # USB port drivers
@@ -1053,56 +1316,85 @@ CONFIG_USB_EGALAX=m
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
-CONFIG_USB_CYTHERM=m
-CONFIG_USB_PHIDGETSERVO=m
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
 # CONFIG_USB_TEST is not set
 
 #
+# USB DSL modem support
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# EDAC - error detection and reporting (RAS)
+#
+# CONFIG_EDAC is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+# CONFIG_UDF_FS is not set
 
 #
 # DOS/FAT/NT Filesystems
 #
 CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_MSDOS_FS is not set
 CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1111,12 +1403,12 @@ CONFIG_VFAT_FS=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1138,38 +1430,48 @@ CONFIG_RAMFS=y
 #
 # Network File Systems
 #
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-CONFIG_NFSD_TCP=y
-CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
 # CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
+CONFIG_CIFS=y
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
 
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 
 #
 # Native Language Support
 #
 CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_DEFAULT="iso8859-15"
+# CONFIG_NLS_CODEPAGE_437 is not set
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
+CONFIG_NLS_CODEPAGE_850=y
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -1189,6 +1491,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
@@ -1199,31 +1502,33 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_13 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=y
 
 #
-# Profiling support
+# Instrumentation Support
 #
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+# CONFIG_PROFILING is not set
+# CONFIG_KPROBES is not set
 
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_EARLY_PRINTK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-# CONFIG_FRAME_POINTER is not set
-CONFIG_4KSTACKS=y
 CONFIG_X86_FIND_SMP_CONFIG=y
 CONFIG_X86_MPPARSE=y
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -1232,13 +1537,18 @@ CONFIG_X86_MPPARSE=y
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
-CONFIG_LIBCRC32C=m
-CONFIG_X86_SMP=y
-CONFIG_X86_HT=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_X86_BIOS_REBOOT=y
-CONFIG_X86_TRAMPOLINE=y
-CONFIG_X86_STD_RESOURCES=y
-CONFIG_PC=y
+CONFIG_KTIME_SCALAR=y
index ac9de26..a331cc9 100644 (file)
@@ -269,6 +269,11 @@ SECTIONS {
                *(__ksymtab_gpl)
                __stop___ksymtab_gpl = .;
 
+               /* Kernel symbol table: GPL-future symbols */
+               __start___ksymtab_gpl_future = .;
+               *(__ksymtab_gpl_future)
+               __stop___ksymtab_gpl_future = .;
+
                /* Kernel symbol table: Normal symbols */
                __start___kcrctab = .;
                *(__kcrctab)
@@ -279,6 +284,11 @@ SECTIONS {
                *(__kcrctab_gpl)
                __stop___kcrctab_gpl = .;
 
+               /* Kernel symbol table: GPL-future symbols */
+               __start___kcrctab_gpl_future = .;
+               *(__kcrctab_gpl_future)
+               __stop___kcrctab_gpl_future = .;
+
                /* Kernel symbol table: strings */
                *(__ksymtab_strings)
 
index 3a0f89d..ac2012f 100644 (file)
@@ -602,7 +602,7 @@ config SGI_IP32
          If you want this kernel to run on SGI O2 workstation, say Y here.
 
 config SIBYTE_BIGSUR
-       bool "Support for Sibyte BigSur"
+       bool "Support for Sibyte BCM91480B-BigSur"
        select BOOT_ELF32
        select DMA_COHERENT
        select PCI_DOMAINS
@@ -790,6 +790,7 @@ source "arch/mips/tx4927/Kconfig"
 source "arch/mips/tx4938/Kconfig"
 source "arch/mips/vr41xx/Kconfig"
 source "arch/mips/philips/pnx8550/common/Kconfig"
+source "arch/mips/cobalt/Kconfig"
 
 endmenu
 
@@ -1159,6 +1160,7 @@ config CPU_R4X00
 config CPU_TX49XX
        bool "R49XX"
        depends on SYS_HAS_CPU_TX49XX
+       select CPU_HAS_PREFETCH
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
 
@@ -1581,7 +1583,7 @@ source "mm/Kconfig"
 
 config SMP
        bool "Multi-Processing support"
-       depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP
+       depends on CPU_RM9000 || ((SIBYTE_BCM1x80 || SIBYTE_BCM1x55 || SIBYTE_SB1250 || QEMU) && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP
        ---help---
          This enables support for systems with more than one CPU. If you have
          a system with only one CPU, like most personal computers, say N. If
index 3d8dac6..9a69e0f 100644 (file)
 # for "archclean" cleaning up for this architecture.
 #
 
-as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \
-            -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \
-            else echo "$(2)"; fi ;)
-
 cflags-y :=
 
 #
@@ -38,12 +34,10 @@ else
 endif
 
 ifdef CONFIG_32BIT
-gcc-abi                        = 32
 tool-prefix            = $(32bit-tool-prefix)
 UTS_MACHINE            := mips
 endif
 ifdef CONFIG_64BIT
-gcc-abi                        = 64
 tool-prefix            = $(64bit-tool-prefix)
 UTS_MACHINE            := mips64
 endif
@@ -52,37 +46,27 @@ ifdef CONFIG_CROSSCOMPILE
 CROSS_COMPILE          := $(tool-prefix)
 endif
 
-CHECKFLAGS-y                           += -D__linux__ -D__mips__ \
-                                          -D_MIPS_SZINT=32 \
-                                          -D_ABIO32=1 \
-                                          -D_ABIN32=2 \
-                                          -D_ABI64=3
-CHECKFLAGS-$(CONFIG_32BIT)             += -D_MIPS_SIM=_ABIO32 \
-                                          -D_MIPS_SZLONG=32 \
-                                          -D_MIPS_SZPTR=32 \
-                                          -D__PTRDIFF_TYPE__=int
-CHECKFLAGS-$(CONFIG_64BIT)             += -m64 -D_MIPS_SIM=_ABI64 \
-                                          -D_MIPS_SZLONG=64 \
-                                          -D_MIPS_SZPTR=64 \
-                                          -D__PTRDIFF_TYPE__="long int"
-CHECKFLAGS-$(CONFIG_CPU_BIG_ENDIAN)    += -D__MIPSEB__
-CHECKFLAGS-$(CONFIG_CPU_LITTLE_ENDIAN) += -D__MIPSEL__
-
-CHECKFLAGS                             = $(CHECKFLAGS-y)
+ifdef CONFIG_32BIT
+ld-emul                        = $(32bit-emul)
+vmlinux-32             = vmlinux
+vmlinux-64             = vmlinux.64
+
+cflags-y               += -mabi=32
+endif
 
-ifdef CONFIG_BUILD_ELF64
-gas-abi                        = 64
+ifdef CONFIG_64BIT
 ld-emul                        = $(64bit-emul)
 vmlinux-32             = vmlinux.32
 vmlinux-64             = vmlinux
-else
-gas-abi                        = 32
-ld-emul                        = $(32bit-emul)
-vmlinux-32             = vmlinux
-vmlinux-64             = vmlinux.64
 
-cflags-$(CONFIG_64BIT) += $(call cc-option,-mno-explicit-relocs)
+cflags-y               += -mabi=64
+ifdef CONFIG_BUILD_ELF64
+cflags-y               += $(call cc-option,-mno-explicit-relocs)
+else
+cflags-y               += $(call cc-option,-msym32)
 endif
+endif
+
 
 #
 # GCC uses -G 0 -mabicalls -fpic as default.  We don't want PIC in the kernel
@@ -105,162 +89,44 @@ MODFLAGS                  += -mlong-calls
 # carefully avoid to add it redundantly because gcc 3.3/3.4 complains
 # when fed the toolchain default!
 #
-cflags-$(CONFIG_CPU_BIG_ENDIAN)                += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB)
-cflags-$(CONFIG_CPU_LITTLE_ENDIAN)     += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL)
+cflags-$(CONFIG_CPU_BIG_ENDIAN)                += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB -D__MIPSEB__)
+cflags-$(CONFIG_CPU_LITTLE_ENDIAN)     += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL -D__MIPSEL__)
 
 cflags-$(CONFIG_SB1XXX_CORELIS)        += $(call cc-option,-mno-sched-prolog) \
                                   -fno-omit-frame-pointer
 
 #
-# Use: $(call set_gccflags,<cpu0>,<isa0>,<cpu1>,<isa1>,<isa2>)
-#
-# <cpu0>,<isa0> -- preferred CPU and ISA designations (may require
-#                  recent tools)
-# <cpu1>,<isa1> -- fallback CPU and ISA designations (have to work
-#                  with up to the oldest supported tools)
-# <isa2>        -- an ISA designation used as an ABI selector for
-#                  gcc versions that do not support "-mabi=32"
-#                  (depending on the CPU type, either "mips1" or
-#                  "mips2")
-#
-set_gccflags = $(shell \
-while :; do \
-       cpu=$(1); isa=-$(2); \
-       for gcc_opt in -march= -mcpu=; do \
-               $(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \
-                       -xc /dev/null > /dev/null 2>&1 && \
-                       break 2; \
-       done; \
-       cpu=$(3); isa=-$(4); \
-       for gcc_opt in -march= -mcpu=; do \
-               $(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \
-                       -xc /dev/null > /dev/null 2>&1 && \
-                       break 2; \
-       done; \
-       break; \
-done; \
-gcc_abi=-mabi=$(gcc-abi); gcc_cpu=$$cpu; \
-if $(CC) $$gcc_abi -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then \
-       gcc_isa=$$isa; \
-else \
-       gcc_abi=; gcc_isa=-$(5); \
-fi; \
-gas_abi=-Wa,-$(gcc-abi); gas_cpu=$$cpu; gas_isa=-Wa,$$isa; \
-while :; do \
-       for gas_opt in -Wa,-march= -Wa,-mcpu=; do \
-               $(CC) $$gas_abi $$gas_opt$$cpu $$gas_isa -Wa,-Z -c \
-                       -o /dev/null -xassembler /dev/null > /dev/null 2>&1 && \
-                       break 2; \
-       done; \
-       gas_abi=; gas_opt=; gas_cpu=; gas_isa=; \
-       break; \
-done; \
-if test "$(gcc-abi)" != "$(gas-abi)"; then \
-       gas_abi="-Wa,-$(gas-abi) -Wa,-mgp$(gcc-abi)"; \
-fi; \
-if test "$$gcc_opt" = -march= && test -n "$$gcc_abi"; then \
-       $(CC) $$gcc_abi $$gcc_opt$$gcc_cpu -S -o /dev/null \
-               -xc /dev/null > /dev/null 2>&1 && \
-               gcc_isa=; \
-fi; \
-echo $$gcc_abi $$gcc_opt$$gcc_cpu $$gcc_isa $$gas_abi $$gas_opt$$gas_cpu $$gas_isa)
-
-#
 # CPU-dependent compiler/assembler options for optimization.
 #
-cflags-$(CONFIG_CPU_R3000)     += \
-                       $(call set_gccflags,r3000,mips1,r3000,mips1,mips1)
-CHECKFLAGS-$(CONFIG_CPU_R3000) += -D_MIPS_ISA=_MIPS_ISA_MIPS1
-
-cflags-$(CONFIG_CPU_TX39XX)    += \
-                       $(call set_gccflags,r3900,mips1,r3000,mips1,mips1)
-CHECKFLAGS-$(CONFIG_CPU_TX39XX)        += -D_MIPS_ISA=_MIPS_ISA_MIPS1
-
-cflags-$(CONFIG_CPU_R6000)     += \
-                       $(call set_gccflags,r6000,mips2,r6000,mips2,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R6000) += -D_MIPS_ISA=_MIPS_ISA_MIPS2
-
-cflags-$(CONFIG_CPU_R4300)     += \
-                       $(call set_gccflags,r4300,mips3,r4300,mips3,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R4300) += -D_MIPS_ISA=_MIPS_ISA_MIPS3
-
-cflags-$(CONFIG_CPU_VR41XX)    += \
-                       $(call set_gccflags,r4100,mips3,r4600,mips3,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_VR41XX)        += -D_MIPS_ISA=_MIPS_ISA_MIPS3
-
-cflags-$(CONFIG_CPU_R4X00)     += \
-                       $(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R4X00) += -D_MIPS_ISA=_MIPS_ISA_MIPS3
-
-cflags-$(CONFIG_CPU_TX49XX)    += \
-                       $(call set_gccflags,r4600,mips3,r4600,mips3,mips2)  \
+cflags-$(CONFIG_CPU_R3000)     += -march=r3000
+cflags-$(CONFIG_CPU_TX39XX)    += -march=r3900
+cflags-$(CONFIG_CPU_R6000)     += -march=r6000 -Wa,--trap
+cflags-$(CONFIG_CPU_R4300)     += -march=r4300 -Wa,--trap
+cflags-$(CONFIG_CPU_VR41XX)    += -march=r4100 -Wa,--trap
+cflags-$(CONFIG_CPU_R4X00)     += -march=r4600 -Wa,--trap
+cflags-$(CONFIG_CPU_TX49XX)    += -march=r4600 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips2 -mtune=r4600) \
+                       -Wa,-mips32 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips2 -mtune=r4600) \
+                       -Wa,-mips32r2 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips2 -mtune=r4600) \
+                       -Wa,-mips64 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips2 -mtune=r4600 ) \
+                       -Wa,-mips64r2 -Wa,--trap
+cflags-$(CONFIG_CPU_R5000)     += -march=r5000 -Wa,--trap
+cflags-$(CONFIG_CPU_R5432)     += $(call cc-options,-march=r5400,-march=r5000) \
                        -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_TX49XX)        += -D_MIPS_ISA=_MIPS_ISA_MIPS3
-
-cflags-$(CONFIG_CPU_MIPS32_R1) += \
-                       $(call set_gccflags,mips32,mips32,r4600,mips3,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_MIPS32_R1)     += -D_MIPS_ISA=_MIPS_ISA_MIPS32
-
-cflags-$(CONFIG_CPU_MIPS32_R2) += \
-                       $(call set_gccflags,mips32r2,mips32r2,r4600,mips3,mips2) \
+cflags-$(CONFIG_CPU_NEVADA)    += $(call cc-options,-march=rm5200,-march=r5000) \
                        -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_MIPS32_R2)     += -D_MIPS_ISA=_MIPS_ISA_MIPS32
-
-cflags-$(CONFIG_CPU_MIPS64_R1) += \
-                       $(call set_gccflags,mips64,mips64,r4600,mips3,mips2) \
+cflags-$(CONFIG_CPU_RM7000)    += $(call cc-option,-march=rm7000,-march=r5000) \
                        -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_MIPS64_R1)     += -D_MIPS_ISA=_MIPS_ISA_MIPS64
-
-cflags-$(CONFIG_CPU_MIPS64_R2) += \
-                       $(call set_gccflags,mips64r2,mips64r2,r4600,mips3,mips2) \
+cflags-$(CONFIG_CPU_RM9000)    += $(call cc-option,-march=rm9000,-march=r5000) \
                        -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_MIPS64_R2)     += -D_MIPS_ISA=_MIPS_ISA_MIPS64
-
-cflags-$(CONFIG_CPU_R5000)     += \
-                       $(call set_gccflags,r5000,mips4,r5000,mips4,mips2) \
+cflags-$(CONFIG_CPU_SB1)       += $(call cc-option,-march=sb1,-march=r5000) \
                        -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R5000) += -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_R5432)     += \
-                       $(call set_gccflags,r5400,mips4,r5000,mips4,mips2) \
+cflags-$(CONFIG_CPU_R8000)     += -march=r8000 -Wa,--trap
+cflags-$(CONFIG_CPU_R10000)    += $(call cc-option,-march=r10000,-march=r8000) \
                        -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R5432) += -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_NEVADA)    += \
-                       $(call set_gccflags,rm5200,mips4,r5000,mips4,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_NEVADA)        += -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_RM7000)    += \
-                       $(call set_gccflags,rm7000,mips4,r5000,mips4,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_RM7000)        += -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_RM9000)    += \
-                       $(call set_gccflags,rm9000,mips4,r5000,mips4,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_RM9000)        += -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-
-cflags-$(CONFIG_CPU_SB1)       += \
-                       $(call set_gccflags,sb1,mips64,r5000,mips4,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_SB1)   += -D_MIPS_ISA=_MIPS_ISA_MIPS64
-
-cflags-$(CONFIG_CPU_R8000)     += \
-                       $(call set_gccflags,r8000,mips4,r8000,mips4,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R8000) += -D_MIPS_ISA=_MIPS_ISA_MIPS4
-
-cflags-$(CONFIG_CPU_R10000)    += \
-                       $(call set_gccflags,r10000,mips4,r8000,mips4,mips2) \
-                       -Wa,--trap
-CHECKFLAGS-$(CONFIG_CPU_R10000)        += -D_MIPS_ISA=_MIPS_ISA_MIPS4
 
 ifdef CONFIG_CPU_SB1
 ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
@@ -630,7 +496,6 @@ endif
 ifdef CONFIG_SGI_IP27
 core-$(CONFIG_SGI_IP27)                += arch/mips/sgi-ip27/
 cflags-$(CONFIG_SGI_IP27)      += -Iinclude/asm-mips/mach-ip27
-ifdef CONFIG_BUILD_ELF64
 ifdef CONFIG_MAPPED_KERNEL
 load-$(CONFIG_SGI_IP27)                += 0xc00000004001c000
 OBJCOPYFLAGS                   := --change-addresses=0x3fffffff80000000
@@ -639,16 +504,6 @@ else
 load-$(CONFIG_SGI_IP27)                += 0xa80000000001c000
 OBJCOPYFLAGS                   := --change-addresses=0x57ffffff80000000
 endif
-else
-ifdef CONFIG_MAPPED_KERNEL
-load-$(CONFIG_SGI_IP27)                += 0xffffffffc001c000
-OBJCOPYFLAGS                   := --change-addresses=0xc000000080000000
-dataoffset-$(CONFIG_SGI_IP27)  += 0x01000000
-else
-load-$(CONFIG_SGI_IP27)                += 0xffffffff8001c000
-OBJCOPYFLAGS                   := --change-addresses=0xa800000080000000
-endif
-endif
 endif
 
 #
@@ -757,6 +612,12 @@ CFLAGS             += $(cflags-y)
 
 LDFLAGS                        += -m $(ld-emul)
 
+ifdef CONFIG_MIPS
+CHECKFLAGS += $(shell $(CC) $(CFLAGS) -dM -E -xc /dev/null | \
+       egrep -vw '__GNUC_(MAJOR|MINOR|PATCHLEVEL)__' | \
+       sed -e 's/^\#define /-D/' -e 's/ /="/' -e 's/$$/"/')
+endif
+
 OBJCOPYFLAGS           += --remove-section=.reginfo
 
 #
index 4dbde82..d8df5fd 100644 (file)
@@ -38,7 +38,7 @@ struct cpu_spec       cpu_specs[] = {
     { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
     { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
     { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
-    { 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 },
+    { 0xffffffff, 0x04030201, "Au1200 AC", 1, 0 },
     { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
 };
 
index d00e824..6ee090b 100644 (file)
@@ -214,7 +214,7 @@ au1xxx_ddma_add_device(dbdev_tab_t *dev)
        if ( NULL != p )
        {
                memcpy(p, dev, sizeof(dbdev_tab_t));
-               p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id);
+               p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id);
                ret = p->dev_id;
                new_id++;
 #if 0
@@ -260,7 +260,7 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
        spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags);
        if (!(stp->dev_flags & DEV_FLAGS_INUSE) ||
             (stp->dev_flags & DEV_FLAGS_ANYUSE)) {
-               /* Got source */
+               /* Got source */
                stp->dev_flags |= DEV_FLAGS_INUSE;
                if (!(dtp->dev_flags & DEV_FLAGS_INUSE) ||
                     (dtp->dev_flags & DEV_FLAGS_ANYUSE)) {
index 1905c6b..1d82f22 100644 (file)
@@ -174,7 +174,7 @@ int request_au1000_dma(int dev_id, const char *dev_str,
                return -EINVAL;
 #else
        if (dev_id < 0 || dev_id >= DMA_NUM_DEV)
-               return -EINVAL;
+               return -EINVAL;
 #endif
 
        for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) {
index 48d3f54..32702e5 100644 (file)
@@ -20,7 +20,7 @@
 static struct resource au1xxx_usb_ohci_resources[] = {
        [0] = {
                .start          = USB_OHCI_BASE,
-               .end            = USB_OHCI_BASE + USB_OHCI_LEN,
+               .end            = USB_OHCI_BASE + USB_OHCI_LEN - 1,
                .flags          = IORESOURCE_MEM,
        },
        [1] = {
@@ -264,7 +264,7 @@ static struct resource smc91x_resources[] = {
 
 static struct platform_device smc91x_device = {
        .name           = "smc91x",
-       .id             = -1,
+       .id             = -1,
        .num_resources  = ARRAY_SIZE(smc91x_resources),
        .resource       = smc91x_resources,
 };
@@ -278,9 +278,7 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
        &au1100_lcd_device,
 #endif
 #ifdef CONFIG_SOC_AU1200
-#if 0  /* fixme */
        &au1xxx_usb_ehci_device,
-#endif
        &au1xxx_usb_gdt_device,
        &au1xxx_usb_otg_device,
        &au1200_lcd_device,
@@ -288,7 +286,7 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
        &au1xxx_mmc_device,
 #endif
 #ifdef CONFIG_MIPS_DB1200
-       &smc91x_device,
+       &smc91x_device,
 #endif
 };
 
index eb155c0..1080558 100644 (file)
@@ -90,7 +90,7 @@ void __init plat_setup(void)
        else {
                /* Clear to obtain best system bus performance */
                clear_c0_config(1<<19); /* Clear Config[OD] */
-       }
+       }
 
        argptr = prom_getcmdline();
 
index 883d3f3..f85f152 100644 (file)
@@ -359,7 +359,7 @@ static unsigned long do_fast_cp0_gettimeoffset(void)
                : "hi", "lo", GCC_REG_ACCUM);
 
        /*
-        * Due to possible jiffies inconsistencies, we need to check
+        * Due to possible jiffies inconsistencies, we need to check
         * the result so that we'll get a timer that is monotonic.
         */
        if (res >= USECS_PER_JIFFY)
diff --git a/arch/mips/cobalt/Kconfig b/arch/mips/cobalt/Kconfig
new file mode 100644 (file)
index 0000000..7c42b08
--- /dev/null
@@ -0,0 +1,7 @@
+config EARLY_PRINTK
+       bool "Early console support"
+       depends on MIPS_COBALT
+       help
+         Provide early console support by direct access to the
+         on board UART. The UART must have been previously
+         initialised by the boot loader.
index 3b6b757..720e757 100644 (file)
@@ -4,4 +4,6 @@
 
 obj-y   := irq.o int-handler.o reset.o setup.o
 
+obj-$(CONFIG_EARLY_PRINTK)     += console.o
+
 EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/cobalt/console.c b/arch/mips/cobalt/console.c
new file mode 100644 (file)
index 0000000..45c2d27
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * (C) P. Horton 2006
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <asm/addrspace.h>
+#include <asm/mach-cobalt/cobalt.h>
+
+static void putchar(int c)
+{
+       if(c == '\n')
+               putchar('\r');
+
+       while(!(COBALT_UART[UART_LSR] & UART_LSR_THRE))
+               ;
+
+       COBALT_UART[UART_TX] = c;
+}
+
+static void cons_write(struct console *c, const char *s, unsigned n)
+{
+       while(n-- && *s)
+               putchar(*s++);
+}
+
+static struct console cons_info =
+{
+       .name   = "uart",
+       .write  = cons_write,
+       .flags  = CON_PRINTBUFFER | CON_BOOT,
+       .index  = -1,
+};
+
+void __init cobalt_early_console(void)
+{
+       register_console(&cons_info);
+
+       printk("Cobalt: early console registered\n");
+}
index b9713a7..4f9ea12 100644 (file)
@@ -31,6 +31,7 @@
 extern void cobalt_machine_restart(char *command);
 extern void cobalt_machine_halt(void);
 extern void cobalt_machine_power_off(void);
+extern void cobalt_early_console(void);
 
 int cobalt_board_id;
 
@@ -109,14 +110,6 @@ void __init plat_setup(void)
        /* I/O port resource must include UART and LCD/buttons */
        ioport_resource.end = 0x0fffffff;
 
-       /*
-        * This is a prom style console. We just poke at the
-        *  UART to make it talk.
-        * Only use this console if you really screw up and can't
-        *  get to the stage of setting up a real serial console.
-        */
-       /*ns16550_setup_console();*/
-
        /* request I/O space for devices used on all i[345]86 PCs */
        for (i = 0; i < COBALT_IO_RESOURCES; i++)
                request_resource(&ioport_resource, cobalt_io_resources + i);
@@ -136,6 +129,10 @@ void __init plat_setup(void)
 #ifdef CONFIG_SERIAL_8250
        if (cobalt_board_id > COBALT_BRD_ID_RAQ1) {
 
+#ifdef CONFIG_EARLY_PRINTK
+               cobalt_early_console();
+#endif
+
                uart.line       = 0;
                uart.type       = PORT_UNKNOWN;
                uart.uartclk    = 18432000;
index 89c2157..9e1ae95 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:52 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:52 2006
 #
 CONFIG_MIPS=y
 
@@ -164,26 +164,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -335,6 +337,29 @@ CONFIG_BRIDGE_NETFILTER=y
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -353,47 +378,30 @@ CONFIG_IP_NF_AMANDA=m
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_PHYSDEV=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_CONNBYTES=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
 CONFIG_IP_NF_TARGET_NETMAP=m
 CONFIG_IP_NF_TARGET_SAME=m
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
 CONFIG_IP_NF_NAT_IRC=m
 CONFIG_IP_NF_NAT_FTP=m
 CONFIG_IP_NF_NAT_TFTP=m
@@ -403,13 +411,9 @@ CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -419,26 +423,20 @@ CONFIG_IP_NF_ARP_MANGLE=m
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_PHYSDEV=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -494,6 +492,11 @@ CONFIG_IPDDP_ENCAP=y
 CONFIG_IPDDP_DECAP=y
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -553,7 +556,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -663,7 +665,7 @@ CONFIG_SCSI_LOGGING=y
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=m
 
@@ -696,13 +698,7 @@ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -785,6 +781,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -824,6 +821,7 @@ CONFIG_LAN_SAA9730=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -845,8 +843,6 @@ CONFIG_LAN_SAA9730=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -926,6 +922,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -933,7 +930,6 @@ 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
@@ -971,6 +967,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -1076,6 +1078,7 @@ CONFIG_XFS_QUOTA=y
 CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -1118,6 +1121,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1225,6 +1229,7 @@ CONFIG_NLS_UTF8=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 6fd3537..3298410 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:54 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:53 2006
 #
 CONFIG_MIPS=y
 
@@ -169,29 +169,31 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -247,7 +249,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_BUILD_ELF64=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -309,6 +310,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -457,6 +463,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -478,6 +485,7 @@ CONFIG_MII=y
 CONFIG_NET_SB1250_MAC=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -543,12 +551,15 @@ CONFIG_SERIO_RAW=m
 #
 # CONFIG_VT is not set
 CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
 # CONFIG_ROCKETPORT is not set
 # CONFIG_CYCLADES is not set
 # CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_SPECIALIX is not set
 # CONFIG_SX is not set
@@ -564,7 +575,6 @@ CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -655,6 +665,12 @@ CONFIG_I2C_DEBUG_BUS=y
 CONFIG_I2C_DEBUG_CHIP=y
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -732,12 +748,12 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -770,6 +786,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -831,18 +848,20 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=16
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
index 5261e29..6c2961a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:55 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:54 2006
 #
 CONFIG_MIPS=y
 
@@ -63,9 +63,9 @@ CONFIG_MACH_VR41XX=y
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_TANBAC_TB022X is not set
 # CONFIG_VICTOR_MPC30X is not set
 CONFIG_ZAO_CAPCELLA=y
@@ -90,7 +90,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -103,23 +103,18 @@ CONFIG_CPU_VR41XX=y
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -155,26 +150,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -190,7 +187,6 @@ CONFIG_KMOD=y
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -228,7 +224,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -286,6 +281,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -306,7 +306,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -444,6 +443,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -487,6 +487,7 @@ CONFIG_8139TOO_PIO=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -508,8 +509,6 @@ CONFIG_8139TOO_PIO=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -579,11 +578,6 @@ CONFIG_HW_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -599,7 +593,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -608,7 +601,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # Ftape, the floppy tape device driver
 #
 # CONFIG_DRM is not set
-CONFIG_GPIO_VR41XX=y
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -623,6 +615,12 @@ CONFIG_GPIO_VR41XX=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -704,11 +702,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -741,6 +739,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -803,6 +802,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 1d3ee18..8336b21 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:57 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:55 2006
 #
 CONFIG_MIPS=y
 
@@ -150,26 +150,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -271,6 +273,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -291,7 +298,6 @@ CONFIG_IEEE80211=y
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -364,9 +370,38 @@ CONFIG_BLK_DEV_IDEDISK=y
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# 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_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
 # CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_BLK_DEV_HD is not set
 
@@ -433,11 +468,21 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
 #
-# CONFIG_NET_TULIP is not set
+CONFIG_NET_TULIP=y
+CONFIG_DE2104X=y
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_ULI526X is not set
 # CONFIG_HP100 is not set
 # CONFIG_NET_PCI is not set
 
@@ -453,6 +498,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -473,8 +519,6 @@ CONFIG_NET_ETHERNET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -550,6 +594,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -557,7 +602,6 @@ 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
@@ -595,6 +639,12 @@ CONFIG_COBALT_LCD=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -678,12 +728,12 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -716,6 +766,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -774,6 +825,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 18ac792..7f07140 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:59 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:56 2006
 #
 CONFIG_MIPS=y
 
@@ -151,26 +151,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -285,6 +288,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -312,6 +330,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -320,6 +343,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -332,7 +356,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -395,6 +418,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -512,6 +536,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -625,13 +650,13 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_CS=m
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -676,6 +701,12 @@ CONFIG_SYNCLINK_CS=m
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -773,6 +804,7 @@ CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -805,6 +837,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -909,6 +942,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -963,3 +997,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index 4f55f74..98590ca 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:00 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:57 2006
 #
 CONFIG_MIPS=y
 
@@ -151,26 +151,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -274,6 +277,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -301,6 +319,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -309,6 +332,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -321,7 +345,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -384,6 +407,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -501,6 +525,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -600,13 +625,13 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -644,6 +669,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -772,6 +803,7 @@ CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -804,6 +836,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -908,6 +941,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -962,3 +996,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index 0e5de7d..9288847 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:03 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:58 2006
 #
 CONFIG_MIPS=y
 
@@ -151,27 +151,30 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -279,6 +282,21 @@ CONFIG_NETFILTER=y
 #
 # CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -306,6 +324,11 @@ CONFIG_NETFILTER=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -314,6 +337,7 @@ CONFIG_NETFILTER=y
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -385,6 +409,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -568,6 +593,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_MIPS_AU1X00_ENET is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -665,13 +691,13 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -716,6 +742,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -842,6 +874,7 @@ CONFIG_JFS_FS=y
 # CONFIG_JFS_STATISTICS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -881,6 +914,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -990,6 +1024,7 @@ CONFIG_NLS_UTF8=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1020,3 +1055,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index 86e7be8..5a415b1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:05 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:59 2006
 #
 CONFIG_MIPS=y
 
@@ -153,26 +153,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -293,6 +296,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -320,6 +338,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -328,6 +351,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -340,7 +364,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -403,6 +426,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -561,6 +585,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -581,6 +606,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -601,8 +627,6 @@ CONFIG_MIPS_AU1X00_ENET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # PCMCIA network device support
@@ -692,16 +716,15 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 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
@@ -746,6 +769,12 @@ CONFIG_SYNCLINK_CS=m
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -788,8 +817,6 @@ CONFIG_SOUND=y
 # Advanced Linux Sound Architecture
 #
 CONFIG_SND=m
-CONFIG_SND_AC97_CODEC=m
-CONFIG_SND_AC97_BUS=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
 CONFIG_SND_RAWMIDI=m
@@ -799,13 +826,16 @@ CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
-CONFIG_SND_GENERIC_DRIVER=y
 
 #
 # Generic devices
 #
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
 # CONFIG_SND_DUMMY is not set
 CONFIG_SND_VIRMIDI=m
 CONFIG_SND_MTPAV=m
@@ -815,6 +845,7 @@ CONFIG_SND_MTPAV=m
 #
 # PCI devices
 #
+# CONFIG_SND_AD1889 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -823,38 +854,38 @@ CONFIG_SND_MTPAV=m
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
-# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_YMFPCI is not set
 
 #
 # ALSA MIPS devices
@@ -939,12 +970,14 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
@@ -958,6 +991,7 @@ CONFIG_USB_HIDINPUT=y
 CONFIG_USB_YEALINK=m
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -1057,6 +1091,7 @@ CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -1089,6 +1124,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1193,6 +1229,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1247,3 +1284,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index ea5ab0c..8dc1f18 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:07 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:00 2006
 #
 CONFIG_MIPS=y
 
@@ -152,26 +152,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -292,6 +295,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -319,6 +337,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -327,6 +350,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -339,7 +363,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -402,6 +425,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -593,6 +617,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -613,6 +638,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -633,8 +659,6 @@ CONFIG_MIPS_AU1X00_ENET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # PCMCIA network device support
@@ -732,16 +756,15 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 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
@@ -786,6 +809,12 @@ CONFIG_SYNCLINK_CS=m
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -878,6 +907,7 @@ CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -910,6 +940,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1014,6 +1045,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1068,3 +1100,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index a81e2de..8fae63e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:09 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:02 2006
 #
 CONFIG_MIPS=y
 
@@ -151,26 +151,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -276,6 +278,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -296,7 +303,6 @@ CONFIG_IEEE80211=y
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -445,6 +451,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -469,6 +476,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -489,8 +497,6 @@ CONFIG_NET_ETHERNET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -566,6 +572,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -573,7 +580,6 @@ 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
@@ -611,6 +617,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -669,7 +681,6 @@ CONFIG_FB=y
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -729,11 +740,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -766,6 +777,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -825,6 +837,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index f1c27c2..a0fcd44 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:11 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:02 2006
 #
 CONFIG_MIPS=y
 
@@ -151,26 +151,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -275,6 +277,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -295,7 +302,6 @@ CONFIG_IEEE80211=y
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -414,6 +420,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -453,6 +460,7 @@ CONFIG_PCNET32=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -474,8 +482,6 @@ CONFIG_PCNET32=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -551,6 +557,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -558,7 +565,6 @@ 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
@@ -596,6 +602,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -677,11 +689,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -714,6 +726,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -776,6 +789,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 08a4de6..5a181ea 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:13 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:03 2006
 #
 CONFIG_MIPS=y
 
@@ -150,27 +150,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -278,6 +280,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -298,7 +305,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -436,6 +442,7 @@ CONFIG_CICADA_PHY=m
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 CONFIG_DECLANCE=y
 
 #
@@ -539,6 +546,12 @@ CONFIG_RTC=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -636,12 +649,12 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -674,6 +687,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -734,6 +748,7 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SGI_PARTITION is not set
 CONFIG_ULTRIX_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -750,18 +765,20 @@ CONFIG_ULTRIX_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
index c9070ce..8fbfc06 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:14 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:04 2006
 #
 CONFIG_MIPS=y
 
@@ -63,9 +63,9 @@ CONFIG_MACH_VR41XX=y
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 CONFIG_CASIO_E55=y
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_TANBAC_TB022X is not set
 # CONFIG_VICTOR_MPC30X is not set
 # CONFIG_ZAO_CAPCELLA is not set
@@ -88,7 +88,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -101,23 +101,18 @@ CONFIG_CPU_VR41XX=y
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -153,26 +148,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -188,7 +185,6 @@ CONFIG_KMOD=y
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -223,7 +219,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -278,6 +273,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -298,7 +298,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -433,6 +432,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -531,10 +531,6 @@ CONFIG_HW_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -563,14 +559,12 @@ CONFIG_WATCHDOG=y
 # CONFIG_WDT is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
 #
 # Ftape, the floppy tape device driver
 #
-CONFIG_GPIO_VR41XX=y
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -585,6 +579,12 @@ CONFIG_GPIO_VR41XX=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -665,11 +665,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -702,6 +702,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -763,6 +764,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index aa24d85..f2d43be 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:16 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:05 2006
 #
 CONFIG_MIPS=y
 
@@ -153,26 +153,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -282,6 +284,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -302,7 +309,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -420,6 +426,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -440,6 +447,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -460,8 +468,6 @@ CONFIG_NET_ETHERNET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -545,6 +551,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -552,7 +559,6 @@ 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
@@ -590,6 +596,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -671,11 +683,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -708,6 +720,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -767,6 +780,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index eeed0e5..ac5841c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:18 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:06 2006
 #
 CONFIG_MIPS=y
 
@@ -157,26 +157,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -284,6 +286,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -304,7 +311,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -407,6 +413,7 @@ CONFIG_CICADA_PHY=m
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 CONFIG_MIPS_GT96100ETH=y
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -496,6 +503,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -538,6 +546,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -617,11 +631,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -654,6 +668,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -713,6 +728,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index e56351a..42d5cd7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:20 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:51 2006
 #
 CONFIG_MIPS=y
 
@@ -158,27 +158,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -317,6 +319,28 @@ CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -335,39 +359,23 @@ CONFIG_IP_NF_AMANDA=m
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_CONNBYTES=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -384,13 +392,9 @@ CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -400,25 +404,20 @@ CONFIG_IP_NF_ARP_MANGLE=m
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -445,6 +444,11 @@ CONFIG_SCTP_HMAC_MD5=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -504,7 +508,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -641,6 +644,7 @@ CONFIG_CICADA_PHY=m
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 CONFIG_SGISEEQ=y
 
 #
@@ -787,6 +791,12 @@ CONFIG_MAX_RAW_DEVS=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -892,6 +902,7 @@ CONFIG_XFS_QUOTA=y
 CONFIG_XFS_SECURITY=y
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -934,6 +945,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1007,6 +1019,7 @@ CONFIG_MSDOS_PARTITION=y
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -1062,6 +1075,7 @@ CONFIG_NLS_UTF8=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 58c22cd..8c40590 100644 (file)
@@ -132,6 +132,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_NEED_MULTIPLE_NODES=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=64
 CONFIG_PREEMPT_NONE=y
@@ -158,28 +159,30 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CPUSETS=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -234,7 +237,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_BUILD_ELF64=y
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -290,6 +292,10 @@ CONFIG_TCP_CONG_BIC=y
 #
 # CONFIG_IP_SCTP is not set
 
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
@@ -357,7 +363,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -368,7 +373,7 @@ CONFIG_IEEE80211_CRYPT_TKIP=m
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
+CONFIG_FW_LOADER=y
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -442,7 +447,7 @@ CONFIG_SCSI_LOGGING=y
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=m
 
@@ -470,13 +475,7 @@ CONFIG_SCSI_SAS_ATTRS=m
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 CONFIG_SCSI_QLOGIC_1280=y
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -561,6 +560,7 @@ CONFIG_SGI_IOC3_ETH_HW_TX_CSUM=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -581,6 +581,7 @@ CONFIG_SGI_IOC3_ETH_HW_TX_CSUM=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -601,8 +602,6 @@ CONFIG_SGI_IOC3_ETH_HW_TX_CSUM=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -656,6 +655,7 @@ CONFIG_SERIO_RAW=m
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -706,6 +706,12 @@ CONFIG_SGI_IP27_RTC=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -801,6 +807,7 @@ CONFIG_XFS_QUOTA=y
 CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -834,6 +841,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -894,6 +902,7 @@ CONFIG_MSDOS_PARTITION=y
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -910,6 +919,7 @@ CONFIG_SGI_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_CROSSCOMPILE=y
index a34db6e..7fdcaf5 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:24 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:09 2006
 #
 CONFIG_MIPS=y
 
@@ -158,26 +158,28 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -224,7 +226,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
-# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -286,6 +287,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -306,7 +312,6 @@ CONFIG_IEEE80211=y
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -392,7 +397,7 @@ CONFIG_SCSI_LOGGING=y
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 CONFIG_SCSI_SAS_ATTRS=y
 
@@ -425,13 +430,7 @@ CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -498,6 +497,7 @@ CONFIG_SGI_O2MACE_ETH=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -518,6 +518,7 @@ CONFIG_SGI_O2MACE_ETH=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -538,8 +539,6 @@ CONFIG_SGI_O2MACE_ETH=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -617,6 +616,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -624,7 +624,6 @@ 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
@@ -662,6 +661,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -743,11 +748,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -780,6 +785,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -835,6 +841,7 @@ CONFIG_PARTITION_ADVANCED=y
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -851,6 +858,7 @@ CONFIG_SGI_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index b5fa963..c716996 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:26 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:10 2006
 #
 CONFIG_MIPS=y
 
@@ -153,26 +153,29 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -281,6 +284,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -301,7 +309,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -362,6 +369,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -500,6 +508,7 @@ CONFIG_CICADA_PHY=m
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -593,6 +602,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -635,6 +645,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -728,11 +744,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -765,6 +781,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -826,6 +843,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 7138693..a8376d1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:27 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:11 2006
 #
 CONFIG_MIPS=y
 
@@ -150,26 +150,28 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -280,6 +282,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -300,7 +307,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -440,6 +446,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -460,6 +467,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -480,8 +488,6 @@ CONFIG_NET_ETHERNET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -560,6 +566,7 @@ CONFIG_IT8172_SCR1=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -567,7 +574,6 @@ 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
@@ -604,6 +610,12 @@ CONFIG_RTC=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -685,11 +697,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -722,6 +734,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -781,6 +794,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 14fb468..3160153 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:29 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:12 2006
 #
 CONFIG_MIPS=y
 
@@ -158,27 +158,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -186,6 +187,7 @@ CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
 
@@ -294,7 +296,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -411,6 +412,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -469,8 +471,6 @@ CONFIG_MV643XX_ETH_2=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -515,6 +515,7 @@ CONFIG_IPW2200=m
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -522,7 +523,6 @@ 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
@@ -558,6 +558,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -631,7 +637,6 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -710,6 +715,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index a8ded3d..53fbef1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:31 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:13 2006
 #
 CONFIG_MIPS=y
 
@@ -148,26 +148,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -272,6 +274,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -292,7 +299,6 @@ CONFIG_IEEE80211=y
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -411,6 +417,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -431,6 +438,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -451,8 +459,6 @@ CONFIG_NET_ETHERNET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -529,6 +535,7 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
@@ -545,7 +552,6 @@ CONFIG_SERIAL_NONSTANDARD=y
 # Non-8250 serial port support
 #
 CONFIG_HAS_TXX9_SERIAL=y
-# CONFIG_SERIAL_JSM is not set
 # CONFIG_UNIX98_PTYS is not set
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -583,6 +589,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -641,7 +653,6 @@ CONFIG_FB=y
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -698,11 +709,11 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -735,6 +746,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -794,6 +806,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 6c5df76..ef0fa9f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:33 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:14 2006
 #
 CONFIG_MIPS=y
 
@@ -156,26 +156,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -282,6 +285,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -302,7 +310,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -365,6 +372,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -548,6 +556,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -568,6 +577,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -588,8 +598,6 @@ CONFIG_NET_ETHERNET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -665,6 +673,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -672,7 +681,6 @@ 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
@@ -710,6 +718,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -801,6 +815,7 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -833,6 +848,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -895,6 +911,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index da0677a..367d279 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc5
-# Fri Dec 23 02:21:03 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:15 2006
 #
 CONFIG_MIPS=y
 
@@ -170,26 +170,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -341,6 +343,29 @@ CONFIG_BRIDGE_NETFILTER=y
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -359,40 +384,23 @@ CONFIG_IP_NF_AMANDA=m
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_PHYSDEV=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_CONNBYTES=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -409,13 +417,9 @@ CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -425,26 +429,20 @@ CONFIG_IP_NF_ARP_MANGLE=m
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_PHYSDEV=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -500,6 +498,11 @@ CONFIG_IPDDP_ENCAP=y
 CONFIG_IPDDP_DECAP=y
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -559,7 +562,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -734,13 +736,7 @@ CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=m
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -823,6 +819,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -862,6 +859,7 @@ CONFIG_PCNET32=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -883,8 +881,6 @@ CONFIG_PCNET32=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -961,6 +957,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -968,7 +965,6 @@ 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
@@ -1005,6 +1001,12 @@ CONFIG_RTC=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -1110,6 +1112,7 @@ CONFIG_XFS_QUOTA=y
 CONFIG_XFS_SECURITY=y
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -1152,6 +1155,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1259,6 +1263,7 @@ CONFIG_NLS_UTF8=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index ac39ab7..fe78961 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:37 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:16 2006
 #
 CONFIG_MIPS=y
 
@@ -156,27 +156,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -297,6 +299,11 @@ CONFIG_SCTP_HMAC_MD5=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -525,6 +532,7 @@ CONFIG_SERIO_SERPORT=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -567,6 +575,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -640,11 +654,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=y
 # CONFIG_INOTIFY is not set
@@ -677,6 +691,7 @@ CONFIG_PROC_FS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -738,17 +753,19 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="nfsroot=192.168.192.169:/u1/mipsel,timeo=20 ip=dhcp"
index 2b5ea37..e4620e7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:39 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:17 2006
 #
 CONFIG_MIPS=y
 
@@ -63,9 +63,9 @@ CONFIG_MACH_VR41XX=y
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_TANBAC_TB022X is not set
 CONFIG_VICTOR_MPC30X=y
 # CONFIG_ZAO_CAPCELLA is not set
@@ -90,7 +90,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -103,23 +103,18 @@ CONFIG_CPU_VR41XX=y
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -155,26 +150,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -190,7 +187,6 @@ CONFIG_KMOD=y
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -229,7 +225,6 @@ CONFIG_PCMCIA_IOCTL=y
 # CONFIG_YENTA is not set
 # CONFIG_PD6729 is not set
 # CONFIG_I82092 is not set
-CONFIG_PCMCIA_VRC4173=y
 
 #
 # PCI Hotplug Support
@@ -241,7 +236,6 @@ CONFIG_PCMCIA_VRC4173=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -296,6 +290,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -455,6 +454,7 @@ CONFIG_MII=m
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -604,11 +604,6 @@ CONFIG_HW_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -624,7 +619,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -640,7 +634,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_SYNCLINK_CS is not set
 # CONFIG_CARDMAN_4000 is not set
 # CONFIG_CARDMAN_4040 is not set
-CONFIG_GPIO_VR41XX=y
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -655,6 +648,12 @@ CONFIG_GPIO_VR41XX=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -740,6 +739,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -762,6 +762,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -846,11 +847,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -883,6 +884,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -941,6 +943,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 7ad8718..925d8ad 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:41 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:18 2006
 #
 CONFIG_MIPS=y
 
@@ -159,27 +159,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -291,6 +293,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -324,6 +341,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -332,6 +354,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -344,7 +367,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -426,7 +448,7 @@ CONFIG_SCSI_PROC_FS=y
 # SCSI Transport Attributes
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=m
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=m
 
@@ -455,13 +477,7 @@ CONFIG_ISCSI_TCP=m
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=m
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -528,6 +544,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -567,6 +584,7 @@ CONFIG_E100=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -592,8 +610,6 @@ CONFIG_MV643XX_ETH_2=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -675,6 +691,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -682,7 +699,6 @@ 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
@@ -719,6 +735,12 @@ CONFIG_RTC=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -777,7 +799,6 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -861,6 +882,7 @@ CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -893,6 +915,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -999,6 +1022,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1052,3 +1076,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index e8d6bb3..ee1cf9b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:43 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:19 2006
 #
 CONFIG_MIPS=y
 
@@ -154,26 +154,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -220,7 +222,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -281,6 +282,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -301,7 +307,6 @@ CONFIG_IEEE80211=y
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -420,6 +425,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -440,6 +446,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -461,8 +468,6 @@ CONFIG_NET_ETHERNET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -538,6 +543,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -545,7 +551,6 @@ 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
@@ -583,6 +588,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -664,11 +675,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -701,6 +712,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -763,6 +775,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index f3787b6..d80ff27 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:44 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:20 2006
 #
 CONFIG_MIPS=y
 
@@ -159,26 +159,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -280,6 +282,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -300,7 +307,6 @@ CONFIG_IEEE80211=y
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -403,6 +409,7 @@ CONFIG_CICADA_PHY=y
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -492,6 +499,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -534,6 +542,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -613,11 +627,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -650,6 +664,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -712,6 +727,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index b6126ad..c0f508d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:46 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:21 2006
 #
 CONFIG_MIPS=y
 
@@ -157,26 +157,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -223,7 +225,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -284,6 +285,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -304,7 +310,6 @@ CONFIG_IEEE80211=y
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=y
 CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_CRYPT_TKIP=y
 
 #
 # Device Drivers
@@ -424,6 +429,7 @@ CONFIG_GALILEO_64240_ETH=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -444,6 +450,7 @@ CONFIG_GALILEO_64240_ETH=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -464,8 +471,6 @@ CONFIG_GALILEO_64240_ETH=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=y
 
 #
 # Wan interfaces
@@ -541,6 +546,7 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -548,7 +554,6 @@ 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
@@ -586,6 +591,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -667,11 +678,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -704,6 +715,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -766,6 +778,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 883626a..194b3c7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:48 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:22 2006
 #
 CONFIG_MIPS=y
 
@@ -153,26 +153,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -287,6 +290,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -314,6 +332,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -322,6 +345,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -334,7 +358,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -397,6 +420,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -514,6 +538,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 # CONFIG_MIPS_AU1X00_ENET is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -619,13 +644,13 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -670,6 +695,12 @@ CONFIG_SYNCLINK_CS=m
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -767,6 +798,7 @@ CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -799,6 +831,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -903,6 +936,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -957,3 +991,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index f8fbc77..8985725 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:50 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:24 2006
 #
 CONFIG_MIPS=y
 
@@ -152,26 +152,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -293,6 +296,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -320,6 +338,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -328,6 +351,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -340,7 +364,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -403,6 +426,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -589,6 +613,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -609,6 +634,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -629,8 +655,6 @@ CONFIG_MIPS_AU1X00_ENET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # PCMCIA network device support
@@ -728,16 +752,15 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 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
@@ -782,6 +805,12 @@ CONFIG_SYNCLINK_CS=m
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -874,6 +903,7 @@ CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -906,6 +936,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1010,6 +1041,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1064,3 +1096,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index 3d694cd..adbf997 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:52 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:25 2006
 #
 CONFIG_MIPS=y
 
@@ -152,26 +152,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -293,6 +296,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -320,6 +338,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -328,6 +351,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -340,7 +364,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -403,6 +426,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -589,6 +613,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -609,6 +634,7 @@ CONFIG_MIPS_AU1X00_ENET=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -629,8 +655,6 @@ CONFIG_MIPS_AU1X00_ENET=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # PCMCIA network device support
@@ -720,16 +744,15 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_CS is not set
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 CONFIG_SERIAL_8250_AU1X00=y
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_AU1X00 is not set
 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
@@ -774,6 +797,12 @@ CONFIG_SYNCLINK_CS=m
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -866,6 +895,7 @@ CONFIG_REISERFS_FS_SECURITY=y
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -898,6 +928,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1002,6 +1033,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1056,3 +1088,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index fba624a..b5db700 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:54 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:26 2006
 #
 CONFIG_MIPS=y
 
@@ -151,28 +151,30 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -281,6 +283,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -308,7 +315,7 @@ CONFIG_TCP_CONG_BIC=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -435,7 +442,7 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI Transport Attributes
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_SAS_ATTRS is not set
 
@@ -464,13 +471,7 @@ CONFIG_ISCSI_TCP=m
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -528,6 +529,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -571,6 +573,7 @@ CONFIG_8139TOO_8129=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -668,7 +671,6 @@ CONFIG_HW_CONSOLE=y
 # Non-8250 serial port support
 #
 # CONFIG_SERIAL_IP3106 is not set
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -706,6 +708,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -801,6 +809,8 @@ CONFIG_USB_STORAGE_USBAT=y
 CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -823,6 +833,7 @@ CONFIG_USB_STORAGE_JUMPSHOT=y
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -906,11 +917,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -946,6 +957,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1049,18 +1061,20 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
index 4c650e7..4187287 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:06:58 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:28 2006
 #
 CONFIG_MIPS=y
 
@@ -152,27 +152,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -279,6 +281,21 @@ CONFIG_NETFILTER=y
 #
 # CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -312,6 +329,11 @@ CONFIG_NETFILTER=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -320,6 +342,7 @@ CONFIG_NETFILTER=y
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -339,7 +362,7 @@ CONFIG_NETFILTER=y
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -466,7 +489,7 @@ CONFIG_BLK_DEV_SD=y
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=m
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_SAS_ATTRS is not set
 
@@ -500,13 +523,7 @@ CONFIG_AIC7XXX_DEBUG_MASK=0
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -564,6 +581,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -607,6 +625,7 @@ CONFIG_8139TOO=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -721,6 +740,7 @@ CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_RISCOM8 is not set
 # CONFIG_SPECIALIX is not set
@@ -737,7 +757,6 @@ CONFIG_SERIAL_NONSTANDARD=y
 # Non-8250 serial port support
 #
 # CONFIG_SERIAL_IP3106 is not set
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -825,6 +844,12 @@ CONFIG_I2C_ALGOBIT=m
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -863,6 +888,7 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
 # CONFIG_SENSORS_W83781D is not set
 # CONFIG_SENSORS_W83792D is not set
 # CONFIG_SENSORS_W83L785TS is not set
@@ -918,7 +944,6 @@ CONFIG_FB=y
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -988,13 +1013,16 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
 # CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
@@ -1008,6 +1036,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -1107,6 +1136,7 @@ CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -1142,6 +1172,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1246,6 +1277,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1299,3 +1331,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index c02beca..31f5afa 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.16-rc2
-# Fri Feb  3 17:14:27 2006
+# Sun Feb 12 19:18:55 2006
 #
 CONFIG_MIPS=y
 
@@ -133,7 +133,6 @@ CONFIG_PREEMPT_NONE=y
 # Code maturity level options
 #
 # CONFIG_EXPERIMENTAL is not set
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -145,7 +144,7 @@ CONFIG_LOCALVERSION_AUTO=y
 # CONFIG_SWAP is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
@@ -222,6 +221,7 @@ CONFIG_NET=y
 #
 # Networking options
 #
+# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -476,8 +476,9 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_LEGACY_PTYS is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
 # IPMI
@@ -627,7 +628,7 @@ CONFIG_FUSE_FS=y
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
-# CONFIG_SYSFS is not set
+CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
@@ -680,12 +681,13 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="console=ttyS0 debug ip=172.20.0.2:172.20.0.1::255.255.0.0"
+CONFIG_CMDLINE=""
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
 
 #
 # Cryptographic options
index 9aaa430..b126f76 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:03 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:30 2006
 #
 CONFIG_MIPS=y
 
@@ -160,27 +160,30 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-# CONFIG_KOBJECT_UEVENT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SHMEM=y
 CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
 
 #
 # Loadable module support
@@ -291,6 +294,21 @@ CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -324,6 +342,11 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -332,6 +355,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
 
 #
 # Network testing
@@ -407,6 +431,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -598,6 +623,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -654,6 +680,7 @@ CONFIG_NET_PCI=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -687,8 +714,8 @@ CONFIG_NET_RADIO=y
 # Wireless 802.11b ISA/PCI cards support
 #
 # CONFIG_IPW2100 is not set
-# CONFIG_IPW_DEBUG is not set
 CONFIG_IPW2200=m
+# CONFIG_IPW2200_DEBUG is not set
 # CONFIG_HERMES is not set
 # CONFIG_ATMEL is not set
 
@@ -795,7 +822,6 @@ CONFIG_HW_CONSOLE=y
 # Non-8250 serial port support
 #
 CONFIG_HAS_TXX9_SERIAL=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -833,6 +859,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -887,7 +919,6 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 CONFIG_FB_ATY=y
 CONFIG_FB_ATY_CT=y
 # CONFIG_FB_ATY_GENERIC_LCD is not set
-# CONFIG_FB_ATY_XL_INIT is not set
 # CONFIG_FB_ATY_GX is not set
 # CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
@@ -896,7 +927,6 @@ CONFIG_FB_ATY_CT=y
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_SMIVGX is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -958,12 +988,14 @@ CONFIG_USB=y
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
@@ -977,6 +1009,7 @@ CONFIG_USB_HIDDEV=y
 CONFIG_USB_YEALINK=m
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -1078,6 +1111,7 @@ CONFIG_XFS_EXPORT=y
 # CONFIG_XFS_SECURITY is not set
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -1115,6 +1149,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1228,6 +1263,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
@@ -1281,3 +1317,7 @@ CONFIG_CRC32=y
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
index abf6109..463ed3d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:06 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:31 2006
 #
 CONFIG_MIPS=y
 
@@ -161,27 +161,29 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -297,6 +299,28 @@ CONFIG_BRIDGE_NETFILTER=y
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -315,39 +339,23 @@ CONFIG_IP_NF_AMANDA=m
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_PHYSDEV=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -364,13 +372,9 @@ CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -380,26 +384,20 @@ CONFIG_IP_NF_ARP_MANGLE=m
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_PHYSDEV=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -451,6 +449,11 @@ CONFIG_DECNET=m
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -530,7 +533,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -541,7 +543,7 @@ CONFIG_IEEE80211_CRYPT_TKIP=m
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
+CONFIG_FW_LOADER=y
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -657,7 +659,7 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 CONFIG_SCSI_SAS_ATTRS=m
 
@@ -678,6 +680,7 @@ CONFIG_ISCSI_TCP=m
 CONFIG_MEGARAID_NEWGEN=y
 CONFIG_MEGARAID_MM=m
 CONFIG_MEGARAID_MAILBOX=m
+# CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_MEGARAID_SAS is not set
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -704,13 +707,7 @@ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_DC395x is not set
@@ -801,6 +798,7 @@ CONFIG_MII=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -858,6 +856,7 @@ CONFIG_EEPRO100=m
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 CONFIG_VIA_VELOCITY=m
 # CONFIG_TIGON3 is not set
@@ -879,8 +878,6 @@ CONFIG_VIA_VELOCITY=m
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -969,6 +966,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 CONFIG_SERIAL_8250_EXTENDED=y
 # CONFIG_SERIAL_8250_MANY_PORTS is not set
 CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -979,7 +977,6 @@ CONFIG_SERIAL_8250_RSA=y
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=m
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -1021,6 +1018,12 @@ CONFIG_RTC=m
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 CONFIG_W1=m
@@ -1123,12 +1126,15 @@ CONFIG_USB_STORAGE_DPCM=y
 CONFIG_USB_STORAGE_SDDR09=y
 CONFIG_USB_STORAGE_SDDR55=y
 CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=m
 CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
 CONFIG_HID_FF=y
 CONFIG_HID_PID=y
 CONFIG_LOGITECH_FF=y
@@ -1151,6 +1157,7 @@ CONFIG_USB_EGALAX=m
 CONFIG_USB_YEALINK=m
 CONFIG_USB_XPAD=m
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -1309,6 +1316,7 @@ CONFIG_XFS_QUOTA=y
 CONFIG_XFS_SECURITY=y
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -1351,6 +1359,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1432,6 +1441,7 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -1487,6 +1497,7 @@ CONFIG_NLS_UTF8=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 52048c9..da68c3f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:09 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:32 2006
 #
 CONFIG_MIPS=y
 
@@ -173,27 +173,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_CPUSETS=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -247,7 +249,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BUILD_ELF64 is not set
 CONFIG_MIPS32_COMPAT=y
 CONFIG_COMPAT=y
 CONFIG_MIPS32_O32=y
@@ -309,6 +310,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -329,7 +335,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -472,6 +477,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -493,6 +499,7 @@ CONFIG_MII=y
 CONFIG_NET_SB1250_MAC=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -513,8 +520,6 @@ CONFIG_NET_SB1250_MAC=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -560,12 +565,15 @@ CONFIG_SERIO_RAW=m
 #
 # CONFIG_VT is not set
 CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
 # CONFIG_ROCKETPORT is not set
 # CONFIG_CYCLADES is not set
 # CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
 # CONFIG_N_HDLC is not set
 # CONFIG_SPECIALIX is not set
 # CONFIG_SX is not set
@@ -581,7 +589,6 @@ CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -619,6 +626,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -696,12 +709,12 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -734,6 +747,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -795,6 +809,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_CROSSCOMPILE=y
index 41dd708..9a936d7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:10 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:33 2006
 #
 CONFIG_MIPS=y
 
@@ -153,25 +153,28 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-# CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -330,6 +333,7 @@ CONFIG_RAID_ATTRS=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -372,6 +376,12 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -444,7 +454,6 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -481,6 +490,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -513,6 +523,7 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -529,6 +540,7 @@ CONFIG_PARTITION_ADVANCED=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 8396946..c2dee0d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:12 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:34 2006
 #
 CONFIG_MIPS=y
 
@@ -63,11 +63,12 @@ CONFIG_MACH_VR41XX=y
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 CONFIG_TANBAC_TB022X=y
 CONFIG_TANBAC_TB0226=y
+CONFIG_TANBAC_TB0287=y
 # CONFIG_VICTOR_MPC30X is not set
 # CONFIG_ZAO_CAPCELLA is not set
 CONFIG_PCI_VR41XX=y
@@ -91,7 +92,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -104,23 +105,18 @@ CONFIG_CPU_VR41XX=y
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -156,26 +152,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -191,7 +189,6 @@ CONFIG_KMOD=y
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -229,7 +226,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -293,6 +289,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -313,7 +314,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -324,7 +324,7 @@ CONFIG_IEEE80211_CRYPT_TKIP=m
 #
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
 
 #
 # Connector - unified userspace <-> kernelspace linker
@@ -397,7 +397,7 @@ CONFIG_SCSI_MULTI_LUN=y
 # SCSI Transport Attributes
 #
 # CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_ISCSI_ATTRS=m
 # CONFIG_SCSI_SAS_ATTRS is not set
 
@@ -426,13 +426,7 @@ CONFIG_ISCSI_TCP=m
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -499,6 +493,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -538,6 +533,7 @@ CONFIG_EEPRO100=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -559,7 +555,6 @@ CONFIG_EEPRO100=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW2200 is not set
 
 #
 # Wan interfaces
@@ -630,11 +625,6 @@ CONFIG_HW_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -650,7 +640,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -675,6 +664,12 @@ CONFIG_GPIO_VR41XX=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -770,6 +765,8 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -792,6 +789,7 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -877,11 +875,11 @@ CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -914,6 +912,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1021,6 +1020,7 @@ CONFIG_NLS_ISO8859_1=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index ce7b9ed..be99261 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:15 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:35 2006
 #
 CONFIG_MIPS=y
 
@@ -63,11 +63,12 @@ CONFIG_MACH_VR41XX=y
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 # CONFIG_IBM_WORKPAD is not set
+# CONFIG_NEC_CMBVR4133 is not set
 CONFIG_TANBAC_TB022X=y
 # CONFIG_TANBAC_TB0226 is not set
+CONFIG_TANBAC_TB0287=y
 # CONFIG_VICTOR_MPC30X is not set
 # CONFIG_ZAO_CAPCELLA is not set
 CONFIG_PCI_VR41XX=y
@@ -91,7 +92,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -104,23 +105,18 @@ CONFIG_CPU_VR41XX=y
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -156,26 +152,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -191,7 +189,6 @@ CONFIG_KMOD=y
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -229,7 +226,6 @@ CONFIG_MMU=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -294,6 +290,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -314,7 +315,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -436,6 +436,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -480,6 +481,7 @@ CONFIG_R8169=y
 # CONFIG_R8169_NAPI is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
@@ -501,8 +503,6 @@ CONFIG_R8169=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -583,11 +583,6 @@ CONFIG_HW_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -603,7 +598,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -613,7 +607,6 @@ CONFIG_TANBAC_TB0219=y
 # Ftape, the floppy tape device driver
 #
 # CONFIG_DRM is not set
-CONFIG_GPIO_VR41XX=y
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -628,6 +621,12 @@ CONFIG_GPIO_VR41XX=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -715,6 +714,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -737,6 +737,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
 
@@ -840,6 +841,7 @@ CONFIG_XFS_QUOTA=y
 # CONFIG_XFS_SECURITY is not set
 CONFIG_XFS_POSIX_ACL=y
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_ROMFS_FS=m
 CONFIG_INOTIFY=y
@@ -879,6 +881,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -986,6 +989,7 @@ CONFIG_NLS_ISO8859_1=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig
deleted file mode 100644 (file)
index 9534483..0000000
+++ /dev/null
@@ -1,1105 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-mm1
-# Tue Oct 25 00:20:22 2005
-#
-CONFIG_MIPS=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SWAP_PREFETCH=y
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
-# CONFIG_IKCONFIG is not set
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=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
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
-
-#
-# Machine selection
-#
-# CONFIG_MIPS_MTX1 is not set
-# CONFIG_MIPS_BOSPORUS is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1100 is not set
-# CONFIG_MIPS_PB1500 is not set
-# CONFIG_MIPS_PB1550 is not set
-# CONFIG_MIPS_PB1200 is not set
-# CONFIG_MIPS_DB1000 is not set
-# CONFIG_MIPS_DB1100 is not set
-# CONFIG_MIPS_DB1500 is not set
-# CONFIG_MIPS_DB1550 is not set
-# CONFIG_MIPS_DB1200 is not set
-# CONFIG_MIPS_MIRAGE is not set
-# CONFIG_MIPS_COBALT is not set
-# CONFIG_MACH_DECSTATION is not set
-# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_ITE8172 is not set
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_LASAT is not set
-# CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_MIPS_SEAD is not set
-# CONFIG_MIPS_SIM is not set
-# CONFIG_MOMENCO_JAGUAR_ATX is not set
-# CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_3 is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MIPS_XXS1500 is not set
-# CONFIG_PNX8550_V2PCI is not set
-# CONFIG_PNX8550_JBS is not set
-# CONFIG_DDB5074 is not set
-# CONFIG_DDB5476 is not set
-# CONFIG_DDB5477 is not set
-CONFIG_MACH_VR41XX=y
-# CONFIG_PMC_YOSEMITE is not set
-# CONFIG_QEMU is not set
-# CONFIG_SGI_IP22 is not set
-# CONFIG_SGI_IP27 is not set
-# CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_SWARM is not set
-# CONFIG_SIBYTE_SENTOSA is not set
-# CONFIG_SIBYTE_RHONE is not set
-# CONFIG_SIBYTE_CARMEL is not set
-# CONFIG_SIBYTE_PTSWARM is not set
-# CONFIG_SIBYTE_LITTLESUR is not set
-# CONFIG_SIBYTE_CRHINE is not set
-# CONFIG_SIBYTE_CRHONE is not set
-# CONFIG_SNI_RM200_PCI is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_TOSHIBA_RBTX4927 is not set
-# CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_CASIO_E55 is not set
-# CONFIG_IBM_WORKPAD is not set
-# CONFIG_NEC_CMBVR4133 is not set
-CONFIG_TANBAC_TB022X=y
-# CONFIG_TANBAC_TB0226 is not set
-CONFIG_TANBAC_TB0287=y
-# CONFIG_VICTOR_MPC30X is not set
-# CONFIG_ZAO_CAPCELLA is not set
-CONFIG_PCI_VR41XX=y
-# CONFIG_VRC4173 is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-# CONFIG_CPU_BIG_ENDIAN is not set
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
-CONFIG_IRQ_CPU=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-
-#
-# CPU selection
-#
-# CONFIG_CPU_MIPS32_R1 is not set
-# CONFIG_CPU_MIPS32_R2 is not set
-# CONFIG_CPU_MIPS64_R1 is not set
-# CONFIG_CPU_MIPS64_R2 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R6000 is not set
-# CONFIG_CPU_NEVADA is not set
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
-# CONFIG_CPU_RM7000 is not set
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
-
-#
-# Kernel type
-#
-CONFIG_32BIT=y
-# CONFIG_64BIT is not set
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_64KB is not set
-# CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
-CONFIG_CPU_HAS_SYNC=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-
-#
-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
-#
-CONFIG_HW_HAS_PCI=y
-CONFIG_PCI=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_MMU=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_ASK_IP_FIB_HASH=y
-# CONFIG_IP_FIB_TRIE is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
-# CONFIG_NET_IPGRE_BROADCAST is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-CONFIG_INET_TUNNEL=m
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-CONFIG_TCP_CONG_ADVANCED=y
-
-#
-# TCP congestion control
-#
-CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
-# CONFIG_TCP_CONG_HSTCP is not set
-# CONFIG_TCP_CONG_HYBLA is not set
-# CONFIG_TCP_CONG_VEGAS is not set
-# CONFIG_TCP_CONG_SCALABLE is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_UB is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# 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_SVWKS is not set
-CONFIG_BLK_DEV_SIIMAGE=y
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
-
-#
-# SCSI Transport Layers
-#
-# CONFIG_SAS_CLASS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_ARCMSR is not set
-# 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
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-# CONFIG_FUSION_SPI is not set
-# CONFIG_FUSION_FC is not set
-# CONFIG_FUSION_SAS is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-CONFIG_IEEE1394=m
-
-#
-# Subsystem Options
-#
-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_OUI_DB is not set
-CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
-CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
-# CONFIG_IEEE1394_EXPORT_FULL_API is not set
-
-#
-# Device Drivers
-#
-
-#
-# Texas Instruments PCILynx requires I2C
-#
-CONFIG_IEEE1394_OHCI1394=m
-
-#
-# Protocol Drivers
-#
-CONFIG_IEEE1394_VIDEO1394=m
-CONFIG_IEEE1394_SBP2=m
-# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
-CONFIG_IEEE1394_ETH1394=m
-CONFIG_IEEE1394_DV1394=m
-CONFIG_IEEE1394_RAWIO=m
-CONFIG_IEEE1394_CMP=m
-CONFIG_IEEE1394_AMDTP=m
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
-# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_PCI is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-CONFIG_R8169=y
-# CONFIG_R8169_NAPI is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-# CONFIG_HOSTAP is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_KGDBOE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NETPOLL_RX is not set
-# CONFIG_NETPOLL_TRAP is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-# CONFIG_TANBAC_TB0219 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-CONFIG_GPIO_VR41XX=y
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
-# CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia Capabilities Port drivers
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Speakup console speech
-#
-# CONFIG_SPEAKUP is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB=m
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-# CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
-
-#
-# USB Host Controller Drivers
-#
-CONFIG_USB_EHCI_HCD=m
-# CONFIG_USB_EHCI_SPLIT_ISO is not set
-# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-# CONFIG_USB_ISP116X_HCD is not set
-CONFIG_USB_OHCI_HCD=m
-# CONFIG_USB_OHCI_BIG_ENDIAN is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-# CONFIG_USB_UHCI_HCD is not set
-# CONFIG_USB_SL811_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# may also be needed; see USB_STORAGE Help for more information
-#
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_USBAT is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-CONFIG_USB_HIDINPUT=y
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_MTOUCH is not set
-# CONFIG_USB_ITMTOUCH is not set
-# CONFIG_USB_EGALAX is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-
-#
-# USB Multimedia devices
-#
-# CONFIG_USB_DABUSB is not set
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET is not set
-CONFIG_USB_MON=y
-
-#
-# USB port drivers
-#
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_AUERSWALD is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_GOTEMP is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_SISUSBVGA is not set
-# CONFIG_USB_LD is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# SN Devices
-#
-
-#
-# EDAC - error detection and reporting (RAS)
-#
-# CONFIG_EDAC is not set
-
-#
-# Distributed Lock Manager
-#
-# CONFIG_DLM is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISER4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-CONFIG_XFS_FS=y
-CONFIG_XFS_QUOTA=y
-# CONFIG_XFS_SECURITY is not set
-CONFIG_XFS_POSIX_ACL=y
-# CONFIG_XFS_RT is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_ROMFS_FS=m
-CONFIG_INOTIFY=y
-# CONFIG_QUOTA is not set
-CONFIG_QUOTACTL=y
-# CONFIG_DNOTIFY is not set
-# CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=y
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_ASFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=m
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
-
-#
-# Security options
-#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=m
index 02b2551..7132e29 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:17 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:36 2006
 #
 CONFIG_MIPS=y
 
@@ -63,9 +63,9 @@ CONFIG_MACH_VR41XX=y
 # CONFIG_TOSHIBA_JMR3927 is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 # CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_CASIO_E55 is not set
 CONFIG_IBM_WORKPAD=y
+# CONFIG_NEC_CMBVR4133 is not set
 # CONFIG_TANBAC_TB022X is not set
 # CONFIG_VICTOR_MPC30X is not set
 # CONFIG_ZAO_CAPCELLA is not set
@@ -88,7 +88,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5
 # CONFIG_CPU_MIPS64_R2 is not set
 # CONFIG_CPU_R3000 is not set
 # CONFIG_CPU_TX39XX is not set
-CONFIG_CPU_VR41XX=y
+# CONFIG_CPU_VR41XX is not set
 # CONFIG_CPU_R4300 is not set
 # CONFIG_CPU_R4X00 is not set
 # CONFIG_CPU_TX49XX is not set
@@ -101,23 +101,18 @@ CONFIG_CPU_VR41XX=y
 # CONFIG_CPU_RM7000 is not set
 # CONFIG_CPU_RM9000 is not set
 # CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_VR41XX=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
 
 #
 # Kernel type
 #
-CONFIG_32BIT=y
+# CONFIG_32BIT is not set
 # CONFIG_64BIT is not set
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 # CONFIG_MIPS_MT is not set
-# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
 CONFIG_CPU_HAS_SYNC=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -153,26 +148,28 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -188,7 +185,6 @@ CONFIG_KMOD=y
 #
 # Block layer
 #
-# CONFIG_LBD is not set
 
 #
 # IO Schedulers
@@ -234,7 +230,6 @@ CONFIG_PCMCIA_PROBE=y
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
 
 #
 # Networking
@@ -289,6 +284,11 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -309,7 +309,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -445,6 +444,7 @@ CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
@@ -556,10 +556,6 @@ CONFIG_HW_CONSOLE=y
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_VR41XX=y
-CONFIG_SERIAL_VR41XX_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -588,7 +584,6 @@ CONFIG_WATCHDOG=y
 # CONFIG_WDT is not set
 # CONFIG_RTC is not set
 # CONFIG_GEN_RTC is not set
-# CONFIG_RTC_VR41XX is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 
@@ -602,7 +597,6 @@ CONFIG_WATCHDOG=y
 # CONFIG_SYNCLINK_CS is not set
 # CONFIG_CARDMAN_4000 is not set
 # CONFIG_CARDMAN_4040 is not set
-# CONFIG_GPIO_VR41XX is not set
 # CONFIG_RAW_DRIVER is not set
 
 #
@@ -617,6 +611,12 @@ CONFIG_WATCHDOG=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -699,12 +699,12 @@ CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 # CONFIG_EXT2_FS_XIP is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -737,6 +737,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -798,6 +799,7 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 468c2e4..6745785 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:07:19 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:40:37 2006
 #
 CONFIG_MIPS=y
 
@@ -154,8 +154,6 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
@@ -164,19 +162,22 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -184,6 +185,7 @@ CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
@@ -295,7 +297,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -413,6 +414,7 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
 
 #
 # Tulip family network device support
@@ -452,8 +454,6 @@ CONFIG_TITAN_GE=y
 # Wireless LAN (non-hamradio)
 #
 # CONFIG_NET_RADIO is not set
-# CONFIG_IPW_DEBUG is not set
-CONFIG_IPW2200=m
 
 #
 # Wan interfaces
@@ -498,6 +498,7 @@ CONFIG_IPW2200=m
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -505,7 +506,6 @@ 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
@@ -542,6 +542,12 @@ CONFIG_GEN_RTC_X=y
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -615,7 +621,6 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -694,12 +699,13 @@ CONFIG_MSDOS_PARTITION=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_MUTEXES=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -707,6 +713,7 @@ CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 CONFIG_CROSSCOMPILE=y
 CONFIG_CMDLINE=""
index 83d4556..81cb5a7 100644 (file)
@@ -45,7 +45,7 @@ static inline void pmax_setup_memory_region(void)
         */
        for (memory_page = (unsigned char *)CKSEG1 + CHUNK_SIZE;
             mem_err == 0 && memory_page < (unsigned char *)CKSEG1 + 0x1e00000;
-            memory_page += CHUNK_SIZE) {
+            memory_page += CHUNK_SIZE) {
                dummy = *memory_page;
        }
        memcpy((void *)(CKSEG0 + 0x80), &old_handler, 0x80);
index 4f125e9..42d5cd7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc2
-# Thu Nov 24 01:05:49 2005
+# Linux kernel version: 2.6.16-rc1
+# Fri Jan 27 15:39:51 2006
 #
 CONFIG_MIPS=y
 
@@ -158,27 +158,29 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=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
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -317,6 +319,28 @@ CONFIG_NETFILTER=y
 CONFIG_NETFILTER_NETLINK=m
 CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
 
 #
 # IP: Netfilter Configuration
@@ -335,39 +359,23 @@ CONFIG_IP_NF_AMANDA=m
 CONFIG_IP_NF_PPTP=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_PKTTYPE=m
-CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 CONFIG_IP_NF_MATCH_RECENT=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_HELPER=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_REALM=m
-CONFIG_IP_NF_MATCH_SCTP=m
-CONFIG_IP_NF_MATCH_DCCP=m
-CONFIG_IP_NF_MATCH_COMMENT=m
-CONFIG_IP_NF_MATCH_CONNMARK=m
-CONFIG_IP_NF_MATCH_CONNBYTES=m
 CONFIG_IP_NF_MATCH_HASHLIMIT=m
-CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_POLICY=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_TARGET_NFQUEUE=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
@@ -384,13 +392,9 @@ CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_ECN=m
 CONFIG_IP_NF_TARGET_DSCP=m
-CONFIG_IP_NF_TARGET_MARK=m
-CONFIG_IP_NF_TARGET_CLASSIFY=m
 CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_TARGET_CONNMARK=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_TARGET_NOTRACK=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
@@ -400,25 +404,20 @@ CONFIG_IP_NF_ARP_MANGLE=m
 #
 CONFIG_IP6_NF_QUEUE=m
 CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_LIMIT=m
-CONFIG_IP6_NF_MATCH_MAC=m
 CONFIG_IP6_NF_MATCH_RT=m
 CONFIG_IP6_NF_MATCH_OPTS=m
 CONFIG_IP6_NF_MATCH_FRAG=m
 CONFIG_IP6_NF_MATCH_HL=m
 CONFIG_IP6_NF_MATCH_MULTIPORT=m
 CONFIG_IP6_NF_MATCH_OWNER=m
-CONFIG_IP6_NF_MATCH_MARK=m
 CONFIG_IP6_NF_MATCH_IPV6HEADER=m
 CONFIG_IP6_NF_MATCH_AHESP=m
-CONFIG_IP6_NF_MATCH_LENGTH=m
 CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_POLICY=m
 CONFIG_IP6_NF_FILTER=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_TARGET_NFQUEUE=m
 CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_TARGET_MARK=m
 CONFIG_IP6_NF_TARGET_HL=m
 CONFIG_IP6_NF_RAW=m
 
@@ -445,6 +444,11 @@ CONFIG_SCTP_HMAC_MD5=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
 CONFIG_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -504,7 +508,6 @@ CONFIG_IEEE80211=m
 # CONFIG_IEEE80211_DEBUG is not set
 CONFIG_IEEE80211_CRYPT_WEP=m
 CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
 
 #
 # Device Drivers
@@ -641,6 +644,7 @@ CONFIG_CICADA_PHY=m
 #
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
+# CONFIG_DM9000 is not set
 CONFIG_SGISEEQ=y
 
 #
@@ -787,6 +791,12 @@ CONFIG_MAX_RAW_DEVS=256
 # CONFIG_I2C is not set
 
 #
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
 # Dallas's 1-wire bus
 #
 # CONFIG_W1 is not set
@@ -892,6 +902,7 @@ CONFIG_XFS_QUOTA=y
 CONFIG_XFS_SECURITY=y
 # CONFIG_XFS_POSIX_ACL is not set
 # CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
 CONFIG_MINIX_FS=m
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -934,6 +945,7 @@ CONFIG_SYSFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1007,6 +1019,7 @@ CONFIG_MSDOS_PARTITION=y
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 
 #
@@ -1062,6 +1075,7 @@ CONFIG_NLS_UTF8=m
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_CROSSCOMPILE=y
index 4dbcf91..dc752c6 100644 (file)
@@ -248,17 +248,17 @@ loc_call: /*
                and     t2,s1
                sh      t2,JAZZ_IO_IRQ_ENABLE
 
-               nor     s1,zero,s1
+               nor     s1,zero,s1
                jal     do_IRQ
 
-               /*
-                * Reenable interrupt
-                */
+               /*
+                * Reenable interrupt
+                */
                lhu     t2,JAZZ_IO_IRQ_ENABLE
-               or      t2,s1
+               or      t2,s1
                sh      t2,JAZZ_IO_IRQ_ENABLE
 
-               j       ret_from_irq
+               j       ret_from_irq
 
 /*
  * "Jump extender" to reach spurious_interrupt
index 292f8b2..58b3b14 100644 (file)
@@ -291,7 +291,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
                 * for documentation.  Commented out because it shares
                 * it's c0_prid id number with the TX3900.
                 */
-               c->cputype = CPU_R4650;
+               c->cputype = CPU_R4650;
                c->isa_level = MIPS_CPU_ISA_III;
                c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
                c->tlbsize = 48;
@@ -604,7 +604,7 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c)
        case PRID_IMP_AU1_REV2:
                switch ((c->processor_id >> 24) & 0xff) {
                case 0:
-                       c->cputype = CPU_AU1000;
+                       c->cputype = CPU_AU1000;
                        break;
                case 1:
                        c->cputype = CPU_AU1500;
@@ -705,7 +705,7 @@ __init void cpu_probe(void)
                break;
        case PRID_COMP_PHILIPS:
                cpu_probe_philips(c);
-               break;
+               break;
        default:
                c->cputype = CPU_UNKNOWN;
        }
index 83b8986..235ad9f 100644 (file)
@@ -41,7 +41,7 @@
  */
                .align  5
                NESTED(trap_low, GDB_FR_SIZE, sp)
-               .set    noat
+               .set    noat
                .set    noreorder
 
                mfc0    k0, CP0_STATUS
index e00e5f6..013bc93 100644 (file)
@@ -69,7 +69,7 @@
  * Revalidate the inode. This is required for proper NFS attribute caching.
  */
 
-int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
+int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
 {
        struct compat_stat tmp;
 
@@ -106,6 +106,10 @@ sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
        unsigned long error;
 
        error = -EINVAL;
+       if (pgoff & (~PAGE_MASK >> 12))
+               goto out;
+       pgoff >>= PAGE_SHIFT-12;
+
        if (!(flags & MAP_ANONYMOUS)) {
                error = -EBADF;
                file = fget(fd);
@@ -125,7 +129,7 @@ out:
 }
 
 
-asmlinkage int sys_truncate64(const char *path, unsigned int high,
+asmlinkage int sys_truncate64(const char __user *path, unsigned int high,
                              unsigned int low)
 {
        if ((int)high < 0)
@@ -161,12 +165,6 @@ out:
        return error;
 }
 
-asmlinkage int
-sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options)
-{
-       return compat_sys_wait4(pid, stat_addr, options, NULL);
-}
-
 asmlinkage long
 sysn32_waitid(int which, compat_pid_t pid,
              siginfo_t __user *uinfo, int options,
@@ -175,6 +173,7 @@ sysn32_waitid(int which, compat_pid_t pid,
        struct rusage ru;
        long ret;
        mm_segment_t old_fs = get_fs();
+       int si_signo;
 
        if (!access_ok(VERIFY_WRITE, uinfo, sizeof(*uinfo)))
                return -EFAULT;
@@ -184,7 +183,9 @@ sysn32_waitid(int which, compat_pid_t pid,
                         uru ? (struct rusage __user *) &ru : NULL);
        set_fs (old_fs);
 
-       if (ret < 0 || uinfo->si_signo == 0)
+       if (__get_user(si_signo, &uinfo->si_signo))
+               return -EFAULT;
+       if (ret < 0 || si_signo == 0)
                return ret;
 
        if (uru)
@@ -208,14 +209,14 @@ struct sysinfo32 {
        char _f[8];
 };
 
-asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
 {
        struct sysinfo s;
        int ret, err;
        mm_segment_t old_fs = get_fs ();
 
        set_fs (KERNEL_DS);
-       ret = sys_sysinfo(&s);
+       ret = sys_sysinfo((struct sysinfo __user *)&s);
        set_fs (old_fs);
        err = put_user (s.uptime, &info->uptime);
        err |= __put_user (s.loads[0], &info->loads[0]);
@@ -245,11 +246,11 @@ struct rlimit32 {
 };
 
 #ifdef __MIPSEB__
-asmlinkage long sys32_truncate64(const char * path, unsigned long __dummy,
+asmlinkage long sys32_truncate64(const char __user * path, unsigned long __dummy,
        int length_hi, int length_lo)
 #endif
 #ifdef __MIPSEL__
-asmlinkage long sys32_truncate64(const char * path, unsigned long __dummy,
+asmlinkage long sys32_truncate64(const char __user * path, unsigned long __dummy,
        int length_lo, int length_hi)
 #endif
 {
@@ -277,7 +278,7 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long __dummy,
 }
 
 static inline long
-get_tv32(struct timeval *o, struct compat_timeval *i)
+get_tv32(struct timeval *o, struct compat_timeval __user *i)
 {
        return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
                (__get_user(o->tv_sec, &i->tv_sec) |
@@ -285,7 +286,7 @@ get_tv32(struct timeval *o, struct compat_timeval *i)
 }
 
 static inline long
-put_tv32(struct compat_timeval *o, struct timeval *i)
+put_tv32(struct compat_timeval __user *o, struct timeval *i)
 {
        return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
                (__put_user(i->tv_sec, &o->tv_sec) |
@@ -295,7 +296,7 @@ put_tv32(struct compat_timeval *o, struct timeval *i)
 extern struct timezone sys_tz;
 
 asmlinkage int
-sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
+sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
 {
        if (tv) {
                struct timeval ktv;
@@ -310,7 +311,7 @@ sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
        return 0;
 }
 
-static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
+static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
 {
        long usec;
 
@@ -325,7 +326,7 @@ static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
 }
 
 asmlinkage int
-sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
+sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
 {
        struct timespec kts;
        struct timezone ktz;
@@ -343,7 +344,7 @@ sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
 }
 
 asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
-                           unsigned int offset_low, loff_t * result,
+                           unsigned int offset_low, loff_t __user * result,
                            unsigned int origin)
 {
        return sys_llseek(fd, offset_high, offset_low, result, origin);
@@ -353,12 +354,12 @@ asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
    lseek back to original location.  They fail just like lseek does on
    non-seekable files.  */
 
-asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf,
+asmlinkage ssize_t sys32_pread(unsigned int fd, char __user * buf,
                               size_t count, u32 unused, u64 a4, u64 a5)
 {
        ssize_t ret;
        struct file * file;
-       ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+       ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
        loff_t pos;
 
        ret = -EBADF;
@@ -388,12 +389,12 @@ bad_file:
        return ret;
 }
 
-asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf,
+asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char __user * buf,
                                size_t count, u32 unused, u64 a4, u64 a5)
 {
        ssize_t ret;
        struct file * file;
-       ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+       ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
        loff_t pos;
 
        ret = -EBADF;
@@ -426,14 +427,14 @@ bad_file:
 }
 
 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
-       struct compat_timespec *interval)
+       struct compat_timespec __user *interval)
 {
        struct timespec t;
        int ret;
        mm_segment_t old_fs = get_fs ();
 
        set_fs (KERNEL_DS);
-       ret = sys_sched_rr_get_interval(pid, &t);
+       ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
        set_fs (old_fs);
        if (put_user (t.tv_sec, &interval->tv_sec) ||
            __put_user (t.tv_nsec, &interval->tv_nsec))
@@ -551,7 +552,7 @@ struct ipc_kludge32 {
 };
 
 static int
-do_sys32_semctl(int first, int second, int third, void *uptr)
+do_sys32_semctl(int first, int second, int third, void __user *uptr)
 {
        union semun fourth;
        u32 pad;
@@ -562,12 +563,12 @@ do_sys32_semctl(int first, int second, int third, void *uptr)
        if (!uptr)
                return -EINVAL;
        err = -EFAULT;
-       if (get_user (pad, (u32 *)uptr))
+       if (get_user (pad, (u32 __user *)uptr))
                return err;
        if ((third & ~IPC_64) == SETVAL)
                fourth.val = (int)pad;
        else
-               fourth.__pad = (void *)A(pad);
+               fourth.__pad = (void __user *)A(pad);
        switch (third & ~IPC_64) {
        case IPC_INFO:
        case IPC_RMID:
@@ -585,14 +586,14 @@ do_sys32_semctl(int first, int second, int third, void *uptr)
 
        case IPC_STAT:
        case SEM_STAT:
-               fourth.__pad = &s;
+               fourth.__pad = (struct semid64_ds __user *)&s;
                old_fs = get_fs();
                set_fs(KERNEL_DS);
                err = sys_semctl(first, second, third | IPC_64, fourth);
                set_fs(old_fs);
 
                if (third & IPC_64) {
-                       struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad);
+                       struct semid64_ds32 __user *usp64 = (struct semid64_ds32 __user *) A(pad);
 
                        if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
                                err = -EFAULT;
@@ -609,7 +610,7 @@ do_sys32_semctl(int first, int second, int third, void *uptr)
                        err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime);
                        err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems);
                } else {
-                       struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
+                       struct semid_ds32 __user *usp32 = (struct semid_ds32 __user *) A(pad);
 
                        if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
                                err = -EFAULT;
@@ -639,9 +640,9 @@ do_sys32_semctl(int first, int second, int third, void *uptr)
 }
 
 static int
-do_sys32_msgsnd (int first, int second, int third, void *uptr)
+do_sys32_msgsnd (int first, int second, int third, void __user *uptr)
 {
-       struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+       struct msgbuf32 __user *up = (struct msgbuf32 __user *)uptr;
        struct msgbuf *p;
        mm_segment_t old_fs;
        int err;
@@ -660,7 +661,7 @@ do_sys32_msgsnd (int first, int second, int third, void *uptr)
                goto out;
        old_fs = get_fs ();
        set_fs (KERNEL_DS);
-       err = sys_msgsnd (first, p, second, third);
+       err = sys_msgsnd (first, (struct msgbuf __user *)p, second, third);
        set_fs (old_fs);
 out:
        kfree (p);
@@ -670,15 +671,15 @@ out:
 
 static int
 do_sys32_msgrcv (int first, int second, int msgtyp, int third,
-                int version, void *uptr)
+                int version, void __user *uptr)
 {
-       struct msgbuf32 *up;
+       struct msgbuf32 __user *up;
        struct msgbuf *p;
        mm_segment_t old_fs;
        int err;
 
        if (!version) {
-               struct ipc_kludge32 *uipck = (struct ipc_kludge32 *)uptr;
+               struct ipc_kludge32 __user *uipck = (struct ipc_kludge32 __user *)uptr;
                struct ipc_kludge32 ipck;
 
                err = -EINVAL;
@@ -687,7 +688,7 @@ do_sys32_msgrcv (int first, int second, int msgtyp, int third,
                err = -EFAULT;
                if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge32)))
                        goto out;
-               uptr = (void *)AA(ipck.msgp);
+               uptr = (void __user *)AA(ipck.msgp);
                msgtyp = ipck.msgtyp;
        }
 
@@ -699,11 +700,11 @@ do_sys32_msgrcv (int first, int second, int msgtyp, int third,
                goto out;
        old_fs = get_fs ();
        set_fs (KERNEL_DS);
-       err = sys_msgrcv (first, p, second + 4, msgtyp, third);
+       err = sys_msgrcv (first, (struct msgbuf __user *)p, second + 4, msgtyp, third);
        set_fs (old_fs);
        if (err < 0)
                goto free_then_out;
-       up = (struct msgbuf32 *)uptr;
+       up = (struct msgbuf32 __user *)uptr;
        if (put_user (p->mtype, &up->mtype) ||
            __copy_to_user (&up->mtext, p->mtext, err))
                err = -EFAULT;
@@ -714,19 +715,19 @@ out:
 }
 
 static int
-do_sys32_msgctl (int first, int second, void *uptr)
+do_sys32_msgctl (int first, int second, void __user *uptr)
 {
        int err = -EINVAL, err2;
        struct msqid64_ds m;
-       struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr;
-       struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr;
+       struct msqid_ds32 __user *up32 = (struct msqid_ds32 __user *)uptr;
+       struct msqid64_ds32 __user *up64 = (struct msqid64_ds32 __user *)uptr;
        mm_segment_t old_fs;
 
        switch (second & ~IPC_64) {
        case IPC_INFO:
        case IPC_RMID:
        case MSG_INFO:
-               err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
+               err = sys_msgctl (first, second, (struct msqid_ds __user *)uptr);
                break;
 
        case IPC_SET:
@@ -753,7 +754,7 @@ do_sys32_msgctl (int first, int second, void *uptr)
                        break;
                old_fs = get_fs();
                set_fs(KERNEL_DS);
-               err = sys_msgctl(first, second | IPC_64, (struct msqid_ds *)&m);
+               err = sys_msgctl(first, second | IPC_64, (struct msqid_ds __user *)&m);
                set_fs(old_fs);
                break;
 
@@ -761,7 +762,7 @@ do_sys32_msgctl (int first, int second, void *uptr)
        case MSG_STAT:
                old_fs = get_fs();
                set_fs(KERNEL_DS);
-               err = sys_msgctl(first, second | IPC_64, (struct msqid_ds *)&m);
+               err = sys_msgctl(first, second | IPC_64, (struct msqid_ds __user *)&m);
                set_fs(old_fs);
                if (second & IPC_64) {
                        if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {
@@ -815,10 +816,10 @@ do_sys32_msgctl (int first, int second, void *uptr)
 }
 
 static int
-do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+do_sys32_shmat (int first, int second, int third, int version, void __user *uptr)
 {
        unsigned long raddr;
-       u32 *uaddr = (u32 *)A((u32)third);
+       u32 __user *uaddr = (u32 __user *)A((u32)third);
        int err = -EINVAL;
 
        if (version == 1)
@@ -837,11 +838,11 @@ struct shm_info32 {
 };
 
 static int
-do_sys32_shmctl (int first, int second, void *uptr)
+do_sys32_shmctl (int first, int second, void __user *uptr)
 {
-       struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr;
-       struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr;
-       struct shm_info32 *uip = (struct shm_info32 *)uptr;
+       struct shmid64_ds32 __user *up64 = (struct shmid64_ds32 __user *)uptr;
+       struct shmid_ds32 __user *up32 = (struct shmid_ds32 __user *)uptr;
+       struct shm_info32 __user *uip = (struct shm_info32 __user *)uptr;
        int err = -EFAULT, err2;
        struct shmid64_ds s64;
        mm_segment_t old_fs;
@@ -854,7 +855,7 @@ do_sys32_shmctl (int first, int second, void *uptr)
        case IPC_RMID:
        case SHM_LOCK:
        case SHM_UNLOCK:
-               err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
+               err = sys_shmctl(first, second, (struct shmid_ds __user *)uptr);
                break;
        case IPC_SET:
                if (second & IPC_64) {
@@ -870,7 +871,7 @@ do_sys32_shmctl (int first, int second, void *uptr)
                        break;
                old_fs = get_fs();
                set_fs(KERNEL_DS);
-               err = sys_shmctl(first, second & ~IPC_64, &s);
+               err = sys_shmctl(first, second & ~IPC_64, (struct shmid_ds __user *)&s);
                set_fs(old_fs);
                break;
 
@@ -878,7 +879,7 @@ do_sys32_shmctl (int first, int second, void *uptr)
        case SHM_STAT:
                old_fs = get_fs();
                set_fs(KERNEL_DS);
-               err = sys_shmctl(first, second | IPC_64, (void *) &s64);
+               err = sys_shmctl(first, second | IPC_64, (void __user *) &s64);
                set_fs(old_fs);
                if (err < 0)
                        break;
@@ -928,7 +929,7 @@ do_sys32_shmctl (int first, int second, void *uptr)
        case SHM_INFO:
                old_fs = get_fs();
                set_fs(KERNEL_DS);
-               err = sys_shmctl(first, second, (void *)&si);
+               err = sys_shmctl(first, second, (void __user *)&si);
                set_fs(old_fs);
                if (err < 0)
                        break;
@@ -950,11 +951,11 @@ do_sys32_shmctl (int first, int second, void *uptr)
        return err;
 }
 
-static int sys32_semtimedop(int semid, struct sembuf *tsems, int nsems,
-                            const struct compat_timespec *timeout32)
+static int sys32_semtimedop(int semid, struct sembuf __user *tsems, int nsems,
+                            const struct compat_timespec __user *timeout32)
 {
        struct compat_timespec t32;
-       struct timespec *t64 = compat_alloc_user_space(sizeof(*t64));
+       struct timespec __user *t64 = compat_alloc_user_space(sizeof(*t64));
 
        if (copy_from_user(&t32, timeout32, sizeof(t32)))
                return -EFAULT;
@@ -977,11 +978,11 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
        switch (call) {
        case SEMOP:
                /* struct sembuf is the same on 32 and 64bit :)) */
-               err = sys_semtimedop (first, (struct sembuf *)AA(ptr), second,
+               err = sys_semtimedop (first, (struct sembuf __user *)AA(ptr), second,
                                      NULL);
                break;
        case SEMTIMEDOP:
-               err = sys32_semtimedop (first, (struct sembuf *)AA(ptr), second,
+               err = sys32_semtimedop (first, (struct sembuf __user *)AA(ptr), second,
                                      (const struct compat_timespec __user *)AA(fifth));
                break;
        case SEMGET:
@@ -989,36 +990,36 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
                break;
        case SEMCTL:
                err = do_sys32_semctl (first, second, third,
-                                      (void *)AA(ptr));
+                                      (void __user *)AA(ptr));
                break;
 
        case MSGSND:
                err = do_sys32_msgsnd (first, second, third,
-                                      (void *)AA(ptr));
+                                      (void __user *)AA(ptr));
                break;
        case MSGRCV:
                err = do_sys32_msgrcv (first, second, fifth, third,
-                                      version, (void *)AA(ptr));
+                                      version, (void __user *)AA(ptr));
                break;
        case MSGGET:
                err = sys_msgget ((key_t) first, second);
                break;
        case MSGCTL:
-               err = do_sys32_msgctl (first, second, (void *)AA(ptr));
+               err = do_sys32_msgctl (first, second, (void __user *)AA(ptr));
                break;
 
        case SHMAT:
                err = do_sys32_shmat (first, second, third,
-                                     version, (void *)AA(ptr));
+                                     version, (void __user *)AA(ptr));
                break;
        case SHMDT:
-               err = sys_shmdt ((char *)A(ptr));
+               err = sys_shmdt ((char __user *)A(ptr));
                break;
        case SHMGET:
                err = sys_shmget (first, (unsigned)second, third);
                break;
        case SHMCTL:
-               err = do_sys32_shmctl (first, second, (void *)AA(ptr));
+               err = do_sys32_shmctl (first, second, (void __user *)AA(ptr));
                break;
        default:
                err = -EINVAL;
@@ -1029,7 +1030,7 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
 }
 
 asmlinkage long sys32_shmat(int shmid, char __user *shmaddr,
-                         int shmflg, int32_t *addr)
+                         int shmflg, int32_t __user *addr)
 {
        unsigned long raddr;
        int err;
@@ -1054,12 +1055,13 @@ struct sysctl_args32
 
 #ifdef CONFIG_SYSCTL
 
-asmlinkage long sys32_sysctl(struct sysctl_args32 *args)
+asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args)
 {
        struct sysctl_args32 tmp;
        int error;
-       size_t oldlen, *oldlenp = NULL;
-       unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+       size_t oldlen;
+       size_t __user *oldlenp = NULL;
+       unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
 
        if (copy_from_user(&tmp, args, sizeof(tmp)))
                return -EFAULT;
@@ -1071,20 +1073,20 @@ asmlinkage long sys32_sysctl(struct sysctl_args32 *args)
                   basically copy the whole sysctl.c here, and
                   glibc's __sysctl uses rw memory for the structure
                   anyway.  */
-               if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
-                   put_user(oldlen, (size_t *)addr))
+               if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) ||
+                   put_user(oldlen, (size_t __user *)addr))
                        return -EFAULT;
-               oldlenp = (size_t *)addr;
+               oldlenp = (size_t __user *)addr;
        }
 
        lock_kernel();
-       error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
-                         oldlenp, (void *)A(tmp.newval), tmp.newlen);
+       error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval),
+                         oldlenp, (void __user *)A(tmp.newval), tmp.newlen);
        unlock_kernel();
        if (oldlenp) {
                if (!error) {
-                       if (get_user(oldlen, (size_t *)addr) ||
-                           put_user(oldlen, (u32 *)A(tmp.oldlenp)))
+                       if (get_user(oldlen, (size_t __user *)addr) ||
+                           put_user(oldlen, (u32 __user *)A(tmp.oldlenp)))
                                error = -EFAULT;
                }
                copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
@@ -1094,7 +1096,7 @@ asmlinkage long sys32_sysctl(struct sysctl_args32 *args)
 
 #endif /* CONFIG_SYSCTL */
 
-asmlinkage long sys32_newuname(struct new_utsname * name)
+asmlinkage long sys32_newuname(struct new_utsname __user * name)
 {
        int ret = 0;
 
@@ -1129,9 +1131,9 @@ struct ustat32 {
        char            f_fpack[6];
 };
 
-extern asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf);
+extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
 
-asmlinkage int sys32_ustat(dev_t dev, struct ustat32 * ubuf32)
+asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
 {
        int err;
         struct ustat tmp;
@@ -1139,7 +1141,7 @@ asmlinkage int sys32_ustat(dev_t dev, struct ustat32 * ubuf32)
        mm_segment_t old_fs = get_fs();
 
        set_fs(KERNEL_DS);
-       err = sys_ustat(dev, &tmp);
+       err = sys_ustat(dev, (struct ustat __user *)&tmp);
        set_fs (old_fs);
 
        if (err)
@@ -1172,7 +1174,7 @@ struct timex32 {
 
 extern int do_adjtimex(struct timex *);
 
-asmlinkage int sys32_adjtimex(struct timex32 *utp)
+asmlinkage int sys32_adjtimex(struct timex32 __user *utp)
 {
        struct timex txc;
        int ret;
@@ -1228,7 +1230,7 @@ asmlinkage int sys32_adjtimex(struct timex32 *utp)
        return ret;
 }
 
-asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset,
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
        s32 count)
 {
        mm_segment_t old_fs = get_fs();
@@ -1239,7 +1241,7 @@ asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset,
                return -EFAULT;
 
        set_fs(KERNEL_DS);
-       ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+       ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
        set_fs(old_fs);
 
        if (offset && put_user(of, offset))
@@ -1269,7 +1271,7 @@ static unsigned char socketcall_nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
  *  it is set by the callees.
  */
 
-asmlinkage long sys32_socketcall(int call, unsigned int *args32)
+asmlinkage long sys32_socketcall(int call, unsigned int __user *args32)
 {
        unsigned int a[6];
        unsigned int a0,a1;
@@ -1291,7 +1293,7 @@ asmlinkage long sys32_socketcall(int call, unsigned int *args32)
                                            struct sockaddr __user *addr, int __user *addr_len);
        extern asmlinkage long sys_shutdown(int fd, int how);
        extern asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen);
-       extern asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int *optlen);
+       extern asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen);
        extern asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
        extern asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flags);
 
@@ -1411,7 +1413,7 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs)
        newsp = regs.regs[5];
        if (!newsp)
                newsp = regs.regs[29];
-       parent_tidptr = (int *) regs.regs[6];
+       parent_tidptr = (int __user *) regs.regs[6];
 
        /* Use __dummy4 instead of getting it off the stack, so that
           syscall() works.  */
index 86fe15b..84ab959 100644 (file)
@@ -135,6 +135,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                cpu_has_vce ? "%u" : "not available");
        seq_printf(m, fmt, 'D', vced_count);
        seq_printf(m, fmt, 'I', vcei_count);
+       seq_printf(m, "\n");
 
        return 0;
 }
index 092679c..a8f435d 100644 (file)
@@ -60,17 +60,9 @@ ATTRIB_NORET void cpu_idle(void)
        }
 }
 
-extern void do_signal(struct pt_regs *regs);
-extern void do_signal32(struct pt_regs *regs);
-
 /*
  * Native o32 and N64 ABI without DSP ASE
  */
-extern int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set);
-extern int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set, siginfo_t *info);
-
 struct mips_abi mips_abi = {
        .do_signal      = do_signal,
 #ifdef CONFIG_TRAD_SIGNALS
@@ -83,11 +75,6 @@ struct mips_abi mips_abi = {
 /*
  * o32 compatibility on 64-bit kernels, without DSP ASE
  */
-extern int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set);
-extern int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set, siginfo_t *info);
-
 struct mips_abi mips_abi_32 = {
        .do_signal      = do_signal32,
        .setup_frame    = setup_frame_32,
@@ -99,9 +86,6 @@ struct mips_abi mips_abi_32 = {
 /*
  * N32 on 64-bit kernels, without DSP ASE
  */
-extern int setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs,
-        int signr, sigset_t *set, siginfo_t *info);
-
 struct mips_abi mips_abi_n32 = {
        .do_signal      = do_signal,
        .setup_rt_frame = setup_rt_frame_n32
index d9293c5..0cb3b60 100644 (file)
@@ -447,21 +447,10 @@ static inline void resource_init(void)
 {
        int i;
 
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-       /*
-        * The 64bit code in 32bit object format trick can't represent
-        * 64bit wide relocations for linker script symbols.
-        */
-       code_resource.start = CPHYSADDR(&_text);
-       code_resource.end = CPHYSADDR(&_etext) - 1;
-       data_resource.start = CPHYSADDR(&_etext);
-       data_resource.end = CPHYSADDR(&_edata) - 1;
-#else
        code_resource.start = virt_to_phys(&_text);
        code_resource.end = virt_to_phys(&_etext) - 1;
        data_resource.start = virt_to_phys(&_etext);
        data_resource.end = virt_to_phys(&_edata) - 1;
-#endif
 
        /*
         * Request address space for all standard RAM.
index 36bfc25..3ca7862 100644 (file)
@@ -166,11 +166,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
        sp = regs->regs[29];
 
        /*
-        * FPU emulator may have it's own trampoline active just
-        * above the user stack, 16-bytes before the next lowest
-        * 16 byte boundary.  Try to avoid trashing it.
-        */
-       sp -= 32;
+        * FPU emulator may have it's own trampoline active just
+        * above the user stack, 16-bytes before the next lowest
+        * 16 byte boundary.  Try to avoid trashing it.
+        */
+       sp -= 32;
 
        /* This is the X/Open sanctioned signal stack switching.  */
        if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
index c974cc9..402efd2 100644 (file)
@@ -100,8 +100,8 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
 }
 
 #ifdef CONFIG_TRAD_SIGNALS
-asmlinkage int sys_sigaction(int sig, const struct sigaction *act,
-       struct sigaction *oact)
+asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act,
+       struct sigaction __user *oact)
 {
        struct k_sigaction new_ka, old_ka;
        int ret;
@@ -331,7 +331,7 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
        /* Create the ucontext.  */
        err |= __put_user(0, &frame->rs_uc.uc_flags);
        err |= __put_user(NULL, &frame->rs_uc.uc_link);
-       err |= __put_user((void *)current->sas_ss_sp,
+       err |= __put_user((void __user *)current->sas_ss_sp,
                          &frame->rs_uc.uc_stack.ss_sp);
        err |= __put_user(sas_ss_flags(regs->regs[29]),
                          &frame->rs_uc.uc_stack.ss_flags);
index 237cd8a..f32a229 100644 (file)
@@ -163,7 +163,7 @@ static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf)
        return err;
 }
 
-static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t *ubuf)
+static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
 {
        int err = 0;
        unsigned long sig[4];
@@ -195,10 +195,10 @@ save_static_function(sys32_sigsuspend);
 __attribute_used__ noinline static int
 _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
 {
-       compat_sigset_t *uset;
+       compat_sigset_t __user *uset;
        sigset_t newset;
 
-       uset = (compat_sigset_t *) regs.regs[4];
+       uset = (compat_sigset_t __user *) regs.regs[4];
        if (get_sigset(&newset, uset))
                return -EFAULT;
        sigdelsetmask(&newset, ~_BLOCKABLE);
@@ -219,7 +219,7 @@ save_static_function(sys32_rt_sigsuspend);
 __attribute_used__ noinline static int
 _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
 {
-       compat_sigset_t *uset;
+       compat_sigset_t __user *uset;
        sigset_t newset;
        size_t sigsetsize;
 
@@ -228,7 +228,7 @@ _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
        if (sigsetsize != sizeof(compat_sigset_t))
                return -EINVAL;
 
-       uset = (compat_sigset_t *) regs.regs[4];
+       uset = (compat_sigset_t __user *) regs.regs[4];
        if (get_sigset(&newset, uset))
                return -EFAULT;
        sigdelsetmask(&newset, ~_BLOCKABLE);
@@ -236,7 +236,7 @@ _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
        spin_lock_irq(&current->sighand->siglock);
        current->saved_sigmask = current->blocked;
        current->blocked = newset;
-        recalc_sigpending();
+       recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
        current->state = TASK_INTERRUPTIBLE;
@@ -245,8 +245,8 @@ _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
        return -ERESTARTNOHAND;
 }
 
-asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act,
-                               struct sigaction32 *oact)
+asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
+                               struct sigaction32 __user *oact)
 {
        struct k_sigaction new_ka, old_ka;
        int ret;
@@ -272,15 +272,15 @@ asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act,
 
        if (!ret && oact) {
                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
-                        return -EFAULT;
+                       return -EFAULT;
                err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
                err |= __put_user((u32)(u64)old_ka.sa.sa_handler,
                                  &oact->sa_handler);
                err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
-                err |= __put_user(0, &oact->sa_mask.sig[1]);
-                err |= __put_user(0, &oact->sa_mask.sig[2]);
-                err |= __put_user(0, &oact->sa_mask.sig[3]);
-                if (err)
+               err |= __put_user(0, &oact->sa_mask.sig[1]);
+               err |= __put_user(0, &oact->sa_mask.sig[2]);
+               err |= __put_user(0, &oact->sa_mask.sig[3]);
+               if (err)
                        return -EFAULT;
        }
 
@@ -301,7 +301,7 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
                if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
                        return -EFAULT;
                err |= __get_user(sp, &uss->ss_sp);
-               kss.ss_sp = (void *) (long) sp;
+               kss.ss_sp = (void __user *) (long) sp;
                err |= __get_user(kss.ss_size, &uss->ss_size);
                err |= __get_user(kss.ss_flags, &uss->ss_flags);
                if (err)
@@ -316,7 +316,7 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
        if (!ret && uoss) {
                if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
                        return -EFAULT;
-               sp = (int) (long) koss.ss_sp;
+               sp = (int) (unsigned long) koss.ss_sp;
                err |= __put_user(sp, &uoss->ss_sp);
                err |= __put_user(koss.ss_size, &uoss->ss_size);
                err |= __put_user(koss.ss_flags, &uoss->ss_flags);
@@ -527,7 +527,7 @@ _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
        /* The ucontext contains a stack32_t, so we must convert!  */
        if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
                goto badframe;
-       st.ss_sp = (void *)(long) sp;
+       st.ss_sp = (void __user *)(long) sp;
        if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
                goto badframe;
        if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
@@ -624,11 +624,11 @@ static inline void __user *get_sigframe(struct k_sigaction *ka,
        sp = regs->regs[29];
 
        /*
-        * FPU emulator may have it's own trampoline active just
-        * above the user stack, 16-bytes before the next lowest
-        * 16 byte boundary.  Try to avoid trashing it.
-        */
-       sp -= 32;
+        * FPU emulator may have it's own trampoline active just
+        * above the user stack, 16-bytes before the next lowest
+        * 16 byte boundary.  Try to avoid trashing it.
+        */
+       sp -= 32;
 
        /* This is the X/Open sanctioned signal stack switching.  */
        if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
@@ -868,7 +868,7 @@ no_signal:
        }
 }
 
-asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act,
+asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
                                  struct sigaction32 __user *oact,
                                  unsigned int sigsetsize)
 {
@@ -912,7 +912,7 @@ out:
        return ret;
 }
 
-asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t *set,
+asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
        compat_sigset_t __user *oset, unsigned int sigsetsize)
 {
        sigset_t old_set, new_set;
index 3e168c0..477c533 100644 (file)
@@ -87,7 +87,8 @@ save_static_function(sysn32_rt_sigsuspend);
 __attribute_used__ noinline static int
 _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
 {
-       compat_sigset_t __user *unewset, uset;
+       compat_sigset_t __user *unewset;
+       compat_sigset_t uset;
        size_t sigsetsize;
        sigset_t newset;
 
@@ -141,7 +142,7 @@ _sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
        /* The ucontext contains a stack32_t, so we must convert!  */
        if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
                goto badframe;
-       st.ss_sp = (void *)(long) sp;
+       st.ss_sp = (void __user *)(long) sp;
        if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
                goto badframe;
        if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
index 1da2eeb..2aeaa2f 100644 (file)
@@ -162,7 +162,10 @@ asmlinkage unsigned long
 sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
           unsigned long flags, unsigned long fd, unsigned long pgoff)
 {
-       return do_mmap2(addr, len, prot, flags, fd, pgoff);
+       if (pgoff & (~PAGE_MASK >> 12))
+               return -EINVAL;
+
+       return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
 }
 
 save_static_function(sys_fork);
@@ -345,7 +348,7 @@ asmlinkage int sys_ipc (uint call, int first, int second,
                union semun fourth;
                if (!ptr)
                        return -EINVAL;
-               if (get_user(fourth.__pad, (void *__user *) ptr))
+               if (get_user(fourth.__pad, (void __user *__user *) ptr))
                        return -EFAULT;
                return sys_semctl (first, second, third, fourth);
        }
index 005debb..bed0eb6 100644 (file)
@@ -576,7 +576,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                }
 #endif
                /*
-                * Unimplemented operation exception.  If we've got the full
+                * Unimplemented operation exception.  If we've got the full
                 * software emulator on-board, let's use it...
                 *
                 * Force FPU to dump state into task/thread context.  We're
index ca22336..988f8ad 100644 (file)
@@ -16,7 +16,8 @@ SECTIONS
   _image_start = ADDR(.data);
   _image_size = SIZEOF(.data);
 
-  .other : {
-       *(.*)
+  .other :
+  {
+    *(.*)
   }
 }
index a397ecb..ddd5c73 100644 (file)
@@ -98,7 +98,7 @@
        and     s0, s1
 
 #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
-       .set    mips32
+       .set    mips32
        clz     a0, s0
        .set    mips0
        negu    a0
index 9987a85..5b84c7f 100644 (file)
@@ -96,7 +96,7 @@
         andi   a0, s0, CAUSEF_IP3      # delay slot, check hw1 interrupt
 #else
        beq     a0, zero, 1f            # delay slot, check hw3 interrupt
-        andi   a0, s0, CAUSEF_IP5
+        andi   a0, s0, CAUSEF_IP5
 #endif
 
        /* Wheee, combined hardware level zero interrupt. */
index 835f038..da52297 100644 (file)
@@ -42,7 +42,7 @@
        and     s0, s1
 
 #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
-       .set    mips32
+       .set    mips32
        clz     a0, s0
        .set    mips0
        negu    a0
index 1982435..a9f0c2b 100644 (file)
@@ -115,7 +115,7 @@ void prom_prepare_cpus(unsigned int max_cpus)
 #ifdef CONFIG_MIPS_MT_SMTC
        void mipsmt_prepare_cpus(int c);
        /*
-        * As noted above, we can assume a single CPU for now
+        * As noted above, we can assume a single CPU for now
         * but it may be multithreaded.
         */
 
index b0178da..4a62201 100644 (file)
@@ -12,7 +12,7 @@ obj-$(CONFIG_HIGHMEM)         += highmem.o
 obj-$(CONFIG_CPU_MIPS32)       += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_CPU_MIPS64)       += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_CPU_NEVADA)       += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
-obj-$(CONFIG_CPU_R10000)       += c-r4k.o cex-gen.o pg-r4k.o tlb-andes.o
+obj-$(CONFIG_CPU_R10000)       += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_CPU_R3000)                += c-r3k.o tlb-r3k.o pg-r4k.o
 obj-$(CONFIG_CPU_R4300)                += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
 obj-$(CONFIG_CPU_R4X00)                += c-r4k.o cex-gen.o pg-r4k.o tlb-r4k.o
index 27f4fa2..9dd1352 100644 (file)
@@ -129,7 +129,7 @@ static void r3k_flush_icache_range(unsigned long start, unsigned long end)
                        "sb\t$0, 0x014(%0)\n\t"
                        "sb\t$0, 0x018(%0)\n\t"
                        "sb\t$0, 0x01c(%0)\n\t"
-                       "sb\t$0, 0x020(%0)\n\t"
+                       "sb\t$0, 0x020(%0)\n\t"
                        "sb\t$0, 0x024(%0)\n\t"
                        "sb\t$0, 0x028(%0)\n\t"
                        "sb\t$0, 0x02c(%0)\n\t"
@@ -145,7 +145,7 @@ static void r3k_flush_icache_range(unsigned long start, unsigned long end)
                        "sb\t$0, 0x054(%0)\n\t"
                        "sb\t$0, 0x058(%0)\n\t"
                        "sb\t$0, 0x05c(%0)\n\t"
-                       "sb\t$0, 0x060(%0)\n\t"
+                       "sb\t$0, 0x060(%0)\n\t"
                        "sb\t$0, 0x064(%0)\n\t"
                        "sb\t$0, 0x068(%0)\n\t"
                        "sb\t$0, 0x06c(%0)\n\t"
@@ -182,31 +182,31 @@ static void r3k_flush_dcache_range(unsigned long start, unsigned long end)
                        "sb\t$0, 0x004(%0)\n\t"
                        "sb\t$0, 0x008(%0)\n\t"
                        "sb\t$0, 0x00c(%0)\n\t"
-                       "sb\t$0, 0x010(%0)\n\t"
+                       "sb\t$0, 0x010(%0)\n\t"
                        "sb\t$0, 0x014(%0)\n\t"
                        "sb\t$0, 0x018(%0)\n\t"
                        "sb\t$0, 0x01c(%0)\n\t"
-                       "sb\t$0, 0x020(%0)\n\t"
+                       "sb\t$0, 0x020(%0)\n\t"
                        "sb\t$0, 0x024(%0)\n\t"
                        "sb\t$0, 0x028(%0)\n\t"
                        "sb\t$0, 0x02c(%0)\n\t"
-                       "sb\t$0, 0x030(%0)\n\t"
+                       "sb\t$0, 0x030(%0)\n\t"
                        "sb\t$0, 0x034(%0)\n\t"
                        "sb\t$0, 0x038(%0)\n\t"
                        "sb\t$0, 0x03c(%0)\n\t"
-                       "sb\t$0, 0x040(%0)\n\t"
+                       "sb\t$0, 0x040(%0)\n\t"
                        "sb\t$0, 0x044(%0)\n\t"
                        "sb\t$0, 0x048(%0)\n\t"
                        "sb\t$0, 0x04c(%0)\n\t"
-                       "sb\t$0, 0x050(%0)\n\t"
+                       "sb\t$0, 0x050(%0)\n\t"
                        "sb\t$0, 0x054(%0)\n\t"
                        "sb\t$0, 0x058(%0)\n\t"
                        "sb\t$0, 0x05c(%0)\n\t"
-                       "sb\t$0, 0x060(%0)\n\t"
+                       "sb\t$0, 0x060(%0)\n\t"
                        "sb\t$0, 0x064(%0)\n\t"
                        "sb\t$0, 0x068(%0)\n\t"
                        "sb\t$0, 0x06c(%0)\n\t"
-                       "sb\t$0, 0x070(%0)\n\t"
+                       "sb\t$0, 0x070(%0)\n\t"
                        "sb\t$0, 0x074(%0)\n\t"
                        "sb\t$0, 0x078(%0)\n\t"
                        "sb\t$0, 0x07c(%0)\n\t"
index 9572ed4..32b7f6a 100644 (file)
@@ -786,6 +786,7 @@ static void __init probe_pcache(void)
                c->dcache.waybit = 0;
 
                c->options |= MIPS_CPU_CACHE_CDEX_P;
+               c->options |= MIPS_CPU_PREFETCH;
                break;
 
        case CPU_R4000PC:
index f51e180..e4390dc 100644 (file)
@@ -124,7 +124,7 @@ static inline void build_nop(void)
 
 static inline void build_src_pref(int advance)
 {
-       if (!(load_offset & (cpu_dcache_line_size() - 1))) {
+       if (!(load_offset & (cpu_dcache_line_size() - 1)) && advance) {
                union mips_instruction mi;
 
                mi.i_format.opcode     = pref_op;
@@ -166,7 +166,7 @@ static inline void build_load_reg(int reg)
 
 static inline void build_dst_pref(int advance)
 {
-       if (!(store_offset & (cpu_dcache_line_size() - 1))) {
+       if (!(store_offset & (cpu_dcache_line_size() - 1)) && advance) {
                union mips_instruction mi;
 
                mi.i_format.opcode     = pref_op;
@@ -340,6 +340,12 @@ void __init build_clear_page(void)
 
        if (cpu_has_prefetch) {
                switch (current_cpu_data.cputype) {
+               case CPU_TX49XX:
+                       /* TX49 supports only Pref_Load */
+                       pref_offset_clear = 0;
+                       pref_offset_copy = 0;
+                       break;
+
                case CPU_RM9000:
                        /*
                         * As a workaround for erratum G105 which make the
index 9e8ff8b..3b6cc9b 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/bitops.h>
 
 #include <asm/addrspace.h>
 #include <asm/bcache.h>
@@ -43,14 +44,7 @@ static void rm7k_sc_wback_inv(unsigned long addr, unsigned long size)
        /* Catch bad driver code */
        BUG_ON(size == 0);
 
-       a = addr & ~(sc_lsize - 1);
-       end = (addr + size - 1) & ~(sc_lsize - 1);
-       while (1) {
-               flush_scache_line(a);   /* Hit_Writeback_Inv_SD */
-               if (a == end)
-                       break;
-               a += sc_lsize;
-       }
+       blast_scache_range(addr, addr + size);
 
        if (!rm7k_tcache_enabled)
                return;
@@ -74,14 +68,7 @@ static void rm7k_sc_inv(unsigned long addr, unsigned long size)
        /* Catch bad driver code */
        BUG_ON(size == 0);
 
-       a = addr & ~(sc_lsize - 1);
-       end = (addr + size - 1) & ~(sc_lsize - 1);
-       while (1) {
-               invalidate_scache_line(a);      /* Hit_Invalidate_SD */
-               if (a == end)
-                       break;
-               a += sc_lsize;
-       }
+       blast_inv_scache_range(addr, addr + size);
 
        if (!rm7k_tcache_enabled)
                return;
@@ -143,11 +130,17 @@ struct bcache_ops rm7k_sc_ops = {
 
 void __init rm7k_sc_init(void)
 {
+       struct cpuinfo_mips *c = &current_cpu_data;
        unsigned int config = read_c0_config();
 
        if ((config & RM7K_CONF_SC))
                return;
 
+       c->scache.linesz = sc_lsize;
+       c->scache.ways = 4;
+       c->scache.waybit= ffs(scache_size / c->scache.ways) - 1;
+       c->scache.waysize = scache_size / c->scache.ways;
+       c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways);
        printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n",
               (scache_size >> 10), sc_lsize);
 
diff --git a/arch/mips/mm/tlb-andes.c b/arch/mips/mm/tlb-andes.c
deleted file mode 100644 (file)
index 3f422a8..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999 Silicon Graphics, Inc.
- * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com)
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/mmu_context.h>
-
-extern void build_tlb_refill_handler(void);
-
-#define NTLB_ENTRIES       64
-#define NTLB_ENTRIES_HALF  32
-
-void local_flush_tlb_all(void)
-{
-       unsigned long flags;
-       unsigned long old_ctx;
-       unsigned long entry;
-
-       local_irq_save(flags);
-       /* Save old context and create impossible VPN2 value */
-       old_ctx = read_c0_entryhi() & ASID_MASK;
-       write_c0_entryhi(CKSEG0);
-       write_c0_entrylo0(0);
-       write_c0_entrylo1(0);
-
-       entry = read_c0_wired();
-
-       /* Blast 'em all away. */
-       while (entry < NTLB_ENTRIES) {
-               write_c0_index(entry);
-               tlb_write_indexed();
-               entry++;
-       }
-       write_c0_entryhi(old_ctx);
-       local_irq_restore(flags);
-}
-
-void local_flush_tlb_mm(struct mm_struct *mm)
-{
-       int cpu = smp_processor_id();
-       if (cpu_context(cpu, mm) != 0) {
-               drop_mmu_context(mm,cpu);
-       }
-}
-
-void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-                           unsigned long end)
-{
-       struct mm_struct *mm = vma->vm_mm;
-       int cpu = smp_processor_id();
-
-       if (cpu_context(cpu, mm) != 0) {
-               unsigned long flags;
-               int size;
-
-               local_irq_save(flags);
-               size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-               size = (size + 1) >> 1;
-               if (size <= NTLB_ENTRIES_HALF) {
-                       int oldpid = (read_c0_entryhi() & ASID_MASK);
-                       int newpid = (cpu_context(smp_processor_id(), mm)
-                                     & ASID_MASK);
-
-                       start &= (PAGE_MASK << 1);
-                       end += ((PAGE_SIZE << 1) - 1);
-                       end &= (PAGE_MASK << 1);
-                       while(start < end) {
-                               int idx;
-
-                               write_c0_entryhi(start | newpid);
-                               start += (PAGE_SIZE << 1);
-                               tlb_probe();
-                               idx = read_c0_index();
-                               write_c0_entrylo0(0);
-                               write_c0_entrylo1(0);
-                               write_c0_entryhi(CKSEG0);
-                               if(idx < 0)
-                                       continue;
-                               tlb_write_indexed();
-                       }
-                       write_c0_entryhi(oldpid);
-               } else {
-                       drop_mmu_context(mm, cpu);
-               }
-               local_irq_restore(flags);
-       }
-}
-
-void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
-       unsigned long flags;
-       int size;
-
-       size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-       size = (size + 1) >> 1;
-
-       local_irq_save(flags);
-       if (size <= NTLB_ENTRIES_HALF) {
-               int pid = read_c0_entryhi();
-
-               start &= (PAGE_MASK << 1);
-               end += ((PAGE_SIZE << 1) - 1);
-               end &= (PAGE_MASK << 1);
-
-               while (start < end) {
-                       int idx;
-
-                       write_c0_entryhi(start);
-                       start += (PAGE_SIZE << 1);
-                       tlb_probe();
-                       idx = read_c0_index();
-                       write_c0_entrylo0(0);
-                       write_c0_entrylo1(0);
-                       write_c0_entryhi(CKSEG0 + (idx << (PAGE_SHIFT+1)));
-                       if (idx < 0)
-                               continue;
-                       tlb_write_indexed();
-               }
-               write_c0_entryhi(pid);
-       } else {
-               local_flush_tlb_all();
-       }
-       local_irq_restore(flags);
-}
-
-void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-       if (cpu_context(smp_processor_id(), vma->vm_mm) != 0) {
-               unsigned long flags;
-               int oldpid, newpid, idx;
-
-               newpid = (cpu_context(smp_processor_id(), vma->vm_mm) &
-                         ASID_MASK);
-               page &= (PAGE_MASK << 1);
-               local_irq_save(flags);
-               oldpid = (read_c0_entryhi() & ASID_MASK);
-               write_c0_entryhi(page | newpid);
-               tlb_probe();
-               idx = read_c0_index();
-               write_c0_entrylo0(0);
-               write_c0_entrylo1(0);
-               write_c0_entryhi(CKSEG0);
-               if (idx < 0)
-                       goto finish;
-               tlb_write_indexed();
-
-       finish:
-               write_c0_entryhi(oldpid);
-               local_irq_restore(flags);
-       }
-}
-
-/*
- * This one is only used for pages with the global bit set so we don't care
- * much about the ASID.
- */
-void local_flush_tlb_one(unsigned long page)
-{
-       unsigned long flags;
-       int oldpid, idx;
-
-       local_irq_save(flags);
-       page &= (PAGE_MASK << 1);
-       oldpid = read_c0_entryhi() & 0xff;
-       write_c0_entryhi(page);
-       tlb_probe();
-       idx = read_c0_index();
-       write_c0_entrylo0(0);
-       write_c0_entrylo1(0);
-       if (idx >= 0) {
-               /* Make sure all entries differ. */
-               write_c0_entryhi(CKSEG0+(idx<<(PAGE_SHIFT+1)));
-               tlb_write_indexed();
-       }
-       write_c0_entryhi(oldpid);
-
-       local_irq_restore(flags);
-}
-
-/* XXX Simplify this.  On the R10000 writing a TLB entry for an virtual
-   address that already exists will overwrite the old entry and not result
-   in TLB malfunction or TLB shutdown.  */
-void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
-{
-       unsigned long flags;
-       pgd_t *pgdp;
-       pud_t *pudp;
-       pmd_t *pmdp;
-       pte_t *ptep;
-       int idx, pid;
-
-       /*
-        * Handle debugger faulting in for debugee.
-        */
-       if (current->active_mm != vma->vm_mm)
-               return;
-
-       pid = read_c0_entryhi() & ASID_MASK;
-
-       if ((pid != (cpu_context(smp_processor_id(), vma->vm_mm) & ASID_MASK))
-           || (cpu_context(smp_processor_id(), vma->vm_mm) == 0)) {
-               printk(KERN_WARNING
-                      "%s: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n",
-                      __FUNCTION__, (int) (cpu_context(smp_processor_id(),
-                      vma->vm_mm) & ASID_MASK), pid);
-       }
-
-       local_irq_save(flags);
-       address &= (PAGE_MASK << 1);
-       write_c0_entryhi(address | (pid));
-       pgdp = pgd_offset(vma->vm_mm, address);
-       tlb_probe();
-       pudp = pud_offset(pgdp, address);
-       pmdp = pmd_offset(pudp, address);
-       idx = read_c0_index();
-       ptep = pte_offset_map(pmdp, address);
-       write_c0_entrylo0(pte_val(*ptep++) >> 6);
-       write_c0_entrylo1(pte_val(*ptep) >> 6);
-       write_c0_entryhi(address | pid);
-       if (idx < 0) {
-               tlb_write_random();
-       } else {
-               tlb_write_indexed();
-       }
-       write_c0_entryhi(pid);
-       local_irq_restore(flags);
-}
-
-void __init tlb_init(void)
-{
-       /*
-        * You should never change this register:
-        *   - On R4600 1.7 the tlbp never hits for pages smaller than
-        *     the value in the c0_pagemask register.
-        *   - The entire mm handling assumes the c0_pagemask register to
-        *     be set for 4kb pages.
-        */
-       write_c0_pagemask(PM_4K);
-       write_c0_wired(0);
-       write_c0_framemask(0);
-
-        /* From this point on the ARC firmware is dead.  */
-       local_flush_tlb_all();
-
-       /* Did I tell you that ARC SUCKS?  */
-
-       build_tlb_refill_handler();
-}
index 8297970..a865f23 100644 (file)
@@ -424,8 +424,13 @@ void __init tlb_init(void)
        probe_tlb(config);
        write_c0_pagemask(PM_DEFAULT_MASK);
        write_c0_wired(0);
+       write_c0_framemask(0);
        temp_tlb_entry = current_cpu_data.tlbsize - 1;
+
+        /* From this point on the ARC firmware is dead.  */
        local_flush_tlb_all();
 
+       /* Did I tell you that ARC SUCKS?  */
+
        build_tlb_refill_handler();
 }
index ac4f4bf..599b3c2 100644 (file)
@@ -951,7 +951,6 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
        /* No i_nop needed here, since the next insn doesn't touch TMP. */
 
 #ifdef CONFIG_SMP
-# ifdef CONFIG_BUILD_ELF64
        /*
         * 64 bit SMP running in XKPHYS has smp_processor_id() << 3
         * stored in CONTEXT.
@@ -962,18 +961,6 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
        i_daddu(p, ptr, ptr, tmp);
        i_dmfc0(p, tmp, C0_BADVADDR);
        i_ld(p, ptr, rel_lo(pgdc), ptr);
-# else
-       /*
-        * 64 bit SMP running in compat space has the lower part of
-        * &pgd_current[smp_processor_id()] stored in CONTEXT.
-        */
-       if (!in_compat_space_p(pgdc))
-               panic("Invalid page directory address!");
-
-       i_dmfc0(p, ptr, C0_CONTEXT);
-       i_dsra(p, ptr, ptr, 23);
-       i_ld(p, ptr, 0, ptr);
-# endif
 #else
        i_LA_mostly(p, ptr, pgdc);
        i_ld(p, ptr, rel_lo(pgdc), ptr);
index c4236b1..ce9fb2e 100644 (file)
@@ -32,7 +32,7 @@ void momenco_jaguar_restart(char *command)
 #else
        void *nvram = (void*) 0xfc807000;
 #endif
-       /* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
+       /* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
        writeb(0x84, nvram + 0xff7);
 
        /* wait for the watchdog to go off */
index 2699917..3784c89 100644 (file)
@@ -461,7 +461,7 @@ void __init plat_setup(void)
          unsigned int tbControl;
          tbControl =
            0 << 26 |  /* post trigger delay 0 */
-                   0x2 << 16 |         /* sequential trace mode */
+                   0x2 << 16 |         /* sequential trace mode */
            //      0x0 << 16 |         /* non-sequential trace mode */
            //      0xf << 4 |          /* watchpoints disabled */
            2 << 2 |            /* armed */
index 72b4423..9d86d24 100644 (file)
@@ -34,7 +34,7 @@ void momenco_ocelot_restart(char *command)
        /* base address of timekeeper portion of part */
        void *nvram = (void *) 0xfc807000L;
 
-       /* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
+       /* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
        writeb(0x84, nvram + 0xff7);
 
        /* wait for the watchdog to go off */
index 6a2489f..9dcd154 100644 (file)
@@ -34,7 +34,7 @@ void momenco_ocelot_restart(char *command)
                0xfc807000;
 #endif
 
-       /* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
+       /* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
        writeb(0x84, nvram + 0xff7);
 
        /* wait for the watchdog to go off */
index 03a0ff2..a8a47b4 100644 (file)
@@ -45,7 +45,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 
        /*
         * we have to open the bridges' windows down to 0 because otherwise
-        * we cannot access ISA south bridge I/O registers that get mapped from
+        * we cannot access ISA south bridge I/O registers that get mapped from
         * 0. for example, 8259 PIC would be unaccessible without that
         */
        if(dev->vendor == PCI_VENDOR_ID_INTEL && dev->device == PCI_DEVICE_ID_INTEL_S21152BB) {
index 0406b50..8e57d4c 100644 (file)
@@ -253,9 +253,9 @@ static int write_config_byte(struct pci_config_swap *swap,
 static int prefix##_##rw##_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 star val) \
 { \
        if (size == 1) \
-               return rw##_config_byte(pciswap, bus, devfn, where, (u8 star)val); \
+               return rw##_config_byte(pciswap, bus, devfn, where, (u8 star)val); \
        else if (size == 2) \
-               return rw##_config_word(pciswap, bus, devfn, where, (u16 star)val); \
+               return rw##_config_word(pciswap, bus, devfn, where, (u16 star)val); \
        /* Size must be 4 */ \
        return rw##_config_dword(pciswap, bus, devfn, where, val); \
 }
index 4c0dcfc..0ff0834 100644 (file)
@@ -34,16 +34,16 @@ struct resource pci_mem_resource = {
 };
 
 struct resource tx4938_pcic1_pci_io_resource = {
-               .name   = "PCI1 IO",
-               .start  = 0,
-               .end    = 0,
-               .flags  = IORESOURCE_IO
+       .name   = "PCI1 IO",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_IO
 };
 struct resource tx4938_pcic1_pci_mem_resource = {
-               .name   = "PCI1 mem",
-               .start  = 0,
-               .end    = 0,
-               .flags  = IORESOURCE_MEM
+       .name   = "PCI1 mem",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_MEM
 };
 
 static int mkaddr(int bus, int dev_fn, int where, int *flagsp)
index ca975e7..f4ef1a3 100644 (file)
@@ -100,7 +100,7 @@ static int bcm1480_pci_can_access(struct pci_bus *bus, int devfn)
 
        if (bus->number == 0) {
                devno = PCI_SLOT(devfn);
-               if (bcm1480_bus_status & PCI_DEVICE_MODE)
+               if (bcm1480_bus_status & PCI_DEVICE_MODE)
                        return 0;
                else
                        return 1;
index aca4a2e..a3eebe5 100644 (file)
@@ -95,7 +95,7 @@ static int bcm1480ht_can_access(struct pci_bus *bus, int devfn)
 
        if (bus->number == 0) {
                devno = PCI_SLOT(devfn);
-               if (bcm1480ht_bus_status & PCI_DEVICE_MODE)
+               if (bcm1480ht_bus_status & PCI_DEVICE_MODE)
                        return 0;
        }
        return 1;
index efc96ce..6002d2a 100644 (file)
@@ -379,18 +379,18 @@ int __init bridge_probe(nasid_t nasid, int widget_id, int masterwid)
        bridge = (bridge_t *) RAW_NODE_SWIN_BASE(nasid, widget_id);
 
        /*
-        * Clear all pending interrupts.
-        */
+        * Clear all pending interrupts.
+        */
        bridge->b_int_rst_stat = BRIDGE_IRR_ALL_CLR;
 
        /*
-        * Until otherwise set up, assume all interrupts are from slot 0
-        */
+        * Until otherwise set up, assume all interrupts are from slot 0
+        */
        bridge->b_int_device = 0x0;
 
        /*
-        * swap pio's to pci mem and io space (big windows)
-        */
+        * swap pio's to pci mem and io space (big windows)
+        */
        bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP |
                                 BRIDGE_CTRL_MEM_SWAP;
 
index 5461449..c500e2d 100644 (file)
@@ -251,7 +251,7 @@ void __init arch_init_irq(void)
                if (gic_int_line == (PNX8550_INT_GPIO0 - PNX8550_INT_GIC_MIN)) {
                        /* PCI INT through gpio 8, which is setup in
                         * pnx8550_setup.c and routed to GPIO
-                        * Interrupt Level 0 (GPIO Connection 58).
+                        * Interrupt Level 0 (GPIO Connection 58).
                         * Set it active low. */
 
                        PNX8550_GIC_REQ(gic_int_line) = 0x1E020000;
index 934944a..6a8e8bc 100644 (file)
@@ -3,3 +3,5 @@
 #
 
 obj-y          = q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o
+
+obj-$(CONFIG_SMP) += q-smp.o
diff --git a/arch/mips/qemu/q-smp.c b/arch/mips/qemu/q-smp.c
new file mode 100644 (file)
index 0000000..5a12354
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 by Ralf Baechle (ralf@linux-mips.org)
+ *
+ * Symmetric Uniprocessor (TM) Support
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+/*
+ * Send inter-processor interrupt
+ */
+void core_send_ipi(int cpu, unsigned int action)
+{
+       panic(KERN_ERR "%s called", __FUNCTION__);
+}
+
+/*
+ *  After we've done initial boot, this function is called to allow the
+ *  board code to clean up state, if needed
+ */
+void prom_init_secondary(void)
+{
+}
+
+void prom_smp_finish(void)
+{
+}
+
+/* Hook for after all CPUs are online */
+void prom_cpus_done(void)
+{
+}
+
+void __init prom_prepare_cpus(unsigned int max_cpus)
+{
+       cpus_clear(phys_cpu_present_map);
+}
+
+/*
+ * Firmware CPU startup hook
+ */
+void prom_boot_secondary(int cpu, struct task_struct *idle)
+{
+}
index ef20d9a..ed93a97 100644 (file)
@@ -540,8 +540,8 @@ void __init mem_init(void)
                struct page *end, *p;
 
                /*
-                * This will free up the bootmem, ie, slot 0 memory.
-                */
+                * This will free up the bootmem, ie, slot 0 memory.
+                */
                totalram_pages += free_all_bootmem_node(NODE_DATA(node));
 
                /*
index 2c38770..2f50c79 100644 (file)
@@ -98,7 +98,7 @@ void __init plat_setup(void)
        board_timer_setup = ip32_timer_setup;
 
 #ifdef CONFIG_SERIAL_8250
-       {
+       {
                static struct uart_port o2_serial[2];
 
                memset(o2_serial, 0, sizeof(o2_serial));
index e19e2be..efe5056 100644 (file)
@@ -70,10 +70,10 @@ void __init prom_init(void)
 
        if ((read_c0_prid() & 0xff) == PRID_REV_TX4927) {
                mips_machtype = MACH_TOSHIBA_RBTX4927;
-               toshiba_name  = "TX4927";
+               toshiba_name  = "TX4927";
        } else {
                mips_machtype = MACH_TOSHIBA_RBTX4937;
-               toshiba_name  = "TX4937";
+               toshiba_name  = "TX4937";
        }
 
        msize = tx4927_get_mem_size();
index 5c7ace9..9166cd4 100644 (file)
@@ -684,7 +684,7 @@ void __init tx4938_board_setup(void)
        for (i = 0; i < 8; i++) {
                if (!(tx4938_ebuscptr->cr[i] & 0x8))
                        continue;       /* disabled */
-               rbtx4938_ce_base[i] = (unsigned long)TX4938_EBUSC_BA(i);
+               rbtx4938_ce_base[i] = (unsigned long)TX4938_EBUSC_BA(i);
                txboard_add_phys_region(rbtx4938_ce_base[i], TX4938_EBUSC_SIZE(i));
        }
 
index de0c1b3..ff272b2 100644 (file)
@@ -183,11 +183,11 @@ static inline unsigned long calculate_tclock(uint16_t clkspeed, unsigned long pc
        switch (current_cpu_data.cputype) {
        case CPU_VR4111:
                if (!(clkspeed & DIV2B))
-                       tclock = pclock / 2;
+                       tclock = pclock / 2;
                else if (!(clkspeed & DIV3B))
-                       tclock = pclock / 3;
+                       tclock = pclock / 3;
                else if (!(clkspeed & DIV4B))
-                       tclock = pclock / 4;
+                       tclock = pclock / 4;
                break;
        case CPU_VR4121:
                tclock = pclock / DIVT(clkspeed);
index 5be05f4..5b2ffcc 100644 (file)
                ___start___ksymtab_gpl = .;                                   \
                        *(__ksymtab_gpl)                                      \
                ___stop___ksymtab_gpl = .;                                    \
+               /* Kernel symbol table: GPL-future symbols */                 \
+               ___start___ksymtab_gpl_future = .;                            \
+                       *(__ksymtab_gpl_future)                               \
+               ___stop___ksymtab_gpl_future = .;                             \
                /* Kernel symbol table: strings */                            \
                        *(__ksymtab_strings)                                  \
                /* Kernel symbol table: Normal symbols */                     \
                ___start___kcrctab_gpl = .;                                   \
                        *(__kcrctab_gpl)                                      \
                ___stop___kcrctab_gpl = .;                                    \
+               /* Kernel symbol table: GPL-future symbols */                 \
+               ___start___kcrctab_gpl_future = .;                            \
+                       *(__kcrctab_gpl_future)                               \
+               ___stop___kcrctab_gpl_future = .;                             \
                /* Built-in module parameters */                              \
                . = ALIGN (4) ;                                               \
                ___start___param = .;                                         \
index db57546..64510fd 100644 (file)
 #include <linux/kmod.h>
 #include <linux/kobj_map.h>
 #include <linux/buffer_head.h>
+#include <linux/mutex.h>
 
 #define MAX_PROBE_HASH 255     /* random */
 
 static struct subsystem block_subsys;
 
-static DECLARE_MUTEX(block_subsys_sem);
+static DEFINE_MUTEX(block_subsys_lock);
 
 /*
  * Can be deleted altogether. Later.
@@ -46,7 +47,7 @@ struct blkdev_info {
 /*
  * iterate over a list of blkdev_info structures.  allows
  * the major_names array to be iterated over from outside this file
- * must be called with the block_subsys_sem held
+ * must be called with the block_subsys_lock held
  */
 void *get_next_blkdev(void *dev)
 {
@@ -85,20 +86,20 @@ out:
 
 void *acquire_blkdev_list(void)
 {
-        down(&block_subsys_sem);
+        mutex_lock(&block_subsys_lock);
         return get_next_blkdev(NULL);
 }
 
 void release_blkdev_list(void *dev)
 {
-        up(&block_subsys_sem);
+        mutex_unlock(&block_subsys_lock);
         kfree(dev);
 }
 
 
 /*
  * Count the number of records in the blkdev_list.
- * must be called with the block_subsys_sem held
+ * must be called with the block_subsys_lock held
  */
 int count_blkdev_list(void)
 {
@@ -118,7 +119,7 @@ int count_blkdev_list(void)
 /*
  * extract the major and name values from a blkdev_info struct
  * passed in as a void to *dev.  Must be called with
- * block_subsys_sem held
+ * block_subsys_lock held
  */
 int get_blkdev_info(void *dev, int *major, char **name)
 {
@@ -138,7 +139,7 @@ int register_blkdev(unsigned int major, const char *name)
        struct blk_major_name **n, *p;
        int index, ret = 0;
 
-       down(&block_subsys_sem);
+       mutex_lock(&block_subsys_lock);
 
        /* temporary */
        if (major == 0) {
@@ -183,7 +184,7 @@ int register_blkdev(unsigned int major, const char *name)
                kfree(p);
        }
 out:
-       up(&block_subsys_sem);
+       mutex_unlock(&block_subsys_lock);
        return ret;
 }
 
@@ -197,7 +198,7 @@ int unregister_blkdev(unsigned int major, const char *name)
        int index = major_to_index(major);
        int ret = 0;
 
-       down(&block_subsys_sem);
+       mutex_lock(&block_subsys_lock);
        for (n = &major_names[index]; *n; n = &(*n)->next)
                if ((*n)->major == major)
                        break;
@@ -207,7 +208,7 @@ int unregister_blkdev(unsigned int major, const char *name)
                p = *n;
                *n = p->next;
        }
-       up(&block_subsys_sem);
+       mutex_unlock(&block_subsys_lock);
        kfree(p);
 
        return ret;
@@ -301,7 +302,7 @@ static void *part_start(struct seq_file *part, loff_t *pos)
        struct list_head *p;
        loff_t l = *pos;
 
-       down(&block_subsys_sem);
+       mutex_lock(&block_subsys_lock);
        list_for_each(p, &block_subsys.kset.list)
                if (!l--)
                        return list_entry(p, struct gendisk, kobj.entry);
@@ -318,7 +319,7 @@ static void *part_next(struct seq_file *part, void *v, loff_t *pos)
 
 static void part_stop(struct seq_file *part, void *v)
 {
-       up(&block_subsys_sem);
+       mutex_unlock(&block_subsys_lock);
 }
 
 static int show_partition(struct seq_file *part, void *v)
@@ -377,7 +378,7 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data)
 
 static int __init genhd_device_init(void)
 {
-       bdev_map = kobj_map_init(base_probe, &block_subsys_sem);
+       bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
        blk_dev_init();
        subsystem_register(&block_subsys);
        return 0;
@@ -611,7 +612,7 @@ static void *diskstats_start(struct seq_file *part, loff_t *pos)
        loff_t k = *pos;
        struct list_head *p;
 
-       down(&block_subsys_sem);
+       mutex_lock(&block_subsys_lock);
        list_for_each(p, &block_subsys.kset.list)
                if (!k--)
                        return list_entry(p, struct gendisk, kobj.entry);
@@ -628,7 +629,7 @@ static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
 
 static void diskstats_stop(struct seq_file *part, void *v)
 {
-       up(&block_subsys_sem);
+       mutex_unlock(&block_subsys_lock);
 }
 
 static int diskstats_show(struct seq_file *s, void *v)
index 06817de..b1d063c 100644 (file)
@@ -188,7 +188,7 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
                case SONET_GETDIAG:
                        return get_diag(dev,arg);
                case SONET_SETFRAMING:
-                       if (arg != SONET_FRAME_SONET) return -EINVAL;
+                       if ((int)(unsigned long)arg != SONET_FRAME_SONET) return -EINVAL;
                        return 0;
                case SONET_GETFRAMING:
                        return put_user(SONET_FRAME_SONET,(int __user *)arg) ?
index 07a7f97..29f3d75 100644 (file)
@@ -141,7 +141,7 @@ int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
        return error;
 }
 
-struct sys_device *get_cpu_sysdev(int cpu)
+struct sys_device *get_cpu_sysdev(unsigned cpu)
 {
        if (cpu < NR_CPUS)
                return cpu_sys_devices[cpu];
index e97e911..4723182 100644 (file)
@@ -211,18 +211,20 @@ static int
 fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
 {
        u8 *new_data;
+       int new_size = fw_priv->alloc_size;
 
        if (min_size <= fw_priv->alloc_size)
                return 0;
 
-       new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE);
+       new_size = ALIGN(min_size, PAGE_SIZE);
+       new_data = vmalloc(new_size);
        if (!new_data) {
                printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
                /* Make sure that we don't keep incomplete data */
                fw_load_abort(fw_priv);
                return -ENOMEM;
        }
-       fw_priv->alloc_size += PAGE_SIZE;
+       fw_priv->alloc_size = new_size;
        if (fw_priv->fw->data) {
                memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
                vfree(fw_priv->fw->data);
index b449dae..e87017f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 #include <linux/kdev_t.h>
 #include <linux/kobject.h>
 #include <linux/kobj_map.h>
@@ -25,7 +26,7 @@ struct kobj_map {
                int (*lock)(dev_t, void *);
                void *data;
        } *probes[255];
-       struct semaphore *sem;
+       struct mutex *lock;
 };
 
 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
@@ -53,7 +54,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
                p->range = range;
                p->data = data;
        }
-       down(domain->sem);
+       mutex_lock(domain->lock);
        for (i = 0, p -= n; i < n; i++, p++, index++) {
                struct probe **s = &domain->probes[index % 255];
                while (*s && (*s)->range < range)
@@ -61,7 +62,7 @@ int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
                p->next = *s;
                *s = p;
        }
-       up(domain->sem);
+       mutex_unlock(domain->lock);
        return 0;
 }
 
@@ -75,7 +76,7 @@ void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
        if (n > 255)
                n = 255;
 
-       down(domain->sem);
+       mutex_lock(domain->lock);
        for (i = 0; i < n; i++, index++) {
                struct probe **s;
                for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
@@ -88,7 +89,7 @@ void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
                        }
                }
        }
-       up(domain->sem);
+       mutex_unlock(domain->lock);
        kfree(found);
 }
 
@@ -99,7 +100,7 @@ struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
        unsigned long best = ~0UL;
 
 retry:
-       down(domain->sem);
+       mutex_lock(domain->lock);
        for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
                struct kobject *(*probe)(dev_t, int *, void *);
                struct module *owner;
@@ -120,7 +121,7 @@ retry:
                        module_put(owner);
                        continue;
                }
-               up(domain->sem);
+               mutex_unlock(domain->lock);
                kobj = probe(dev, index, data);
                /* Currently ->owner protects _only_ ->probe() itself. */
                module_put(owner);
@@ -128,11 +129,11 @@ retry:
                        return kobj;
                goto retry;
        }
-       up(domain->sem);
+       mutex_unlock(domain->lock);
        return NULL;
 }
 
-struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
+struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
 {
        struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
        struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
@@ -149,6 +150,6 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
        base->get = base_probe;
        for (i = 0; i < 255; i++)
                p->probes[i] = base;
-       p->sem = sem;
+       p->lock = lock;
        return p;
 }
index 461554a..89b2683 100644 (file)
@@ -61,7 +61,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
 {
        struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
 
-       return r ? r->start : 0;
+       return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(platform_get_irq);
 
@@ -98,7 +98,7 @@ int platform_get_irq_byname(struct platform_device *dev, char *name)
 {
        struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
 
-       return r ? r->start : 0;
+       return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(platform_get_irq_byname);
 
index f04d864..f73446f 100644 (file)
@@ -8,7 +8,6 @@
  * and is not licensed separately. See file COPYING for details.
  *
  * TODO (sorted by decreasing priority)
- *  -- Kill first_open (Al Viro fixed the block layer now)
  *  -- set readonly flag for CDs, set removable flag for CF readers
  *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
  *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
@@ -181,6 +180,7 @@ struct ub_dev;
 #define UB_DIR_ILLEGAL2        2
 #define UB_DIR_WRITE   3
 
+/* P3 */
 #define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
                         (((c)==UB_DIR_READ)? 'r': 'n'))
 
@@ -196,24 +196,11 @@ enum ub_scsi_cmd_state {
        UB_CMDST_DONE                   /* Final state */
 };
 
-static char *ub_scsi_cmd_stname[] = {
-       ".  ",
-       "Cmd",
-       "dat",
-       "c2s",
-       "sts",
-       "clr",
-       "crs",
-       "Sen",
-       "fin"
-};
-
 struct ub_scsi_cmd {
        unsigned char cdb[UB_MAX_CDB_SIZE];
        unsigned char cdb_len;
 
        unsigned char dir;              /* 0 - none, 1 - read, 3 - write. */
-       unsigned char trace_index;
        enum ub_scsi_cmd_state state;
        unsigned int tag;
        struct ub_scsi_cmd *next;
@@ -250,28 +237,6 @@ struct ub_capacity {
 };
 
 /*
- * The SCSI command tracing structure.
- */
-
-#define SCMD_ST_HIST_SZ   8
-#define SCMD_TRACE_SZ    63            /* Less than 4KB of 61-byte lines */
-
-struct ub_scsi_cmd_trace {
-       int hcur;
-       unsigned int tag;
-       unsigned int req_size, act_size;
-       unsigned char op;
-       unsigned char dir;
-       unsigned char key, asc, ascq;
-       char st_hst[SCMD_ST_HIST_SZ];   
-};
-
-struct ub_scsi_trace {
-       int cur;
-       struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ];
-};
-
-/*
  * This is a direct take-off from linux/include/completion.h
  * The difference is that I do not wait on this thing, just poll.
  * When I want to wait (ub_probe), I just use the stock completion.
@@ -334,7 +299,6 @@ struct ub_lun {
        int changed;                    /* Media was changed */
        int removable;
        int readonly;
-       int first_open;                 /* Kludge. See ub_bd_open. */
 
        struct ub_request urq;
 
@@ -390,7 +354,6 @@ struct ub_dev {
        wait_queue_head_t reset_wait;
 
        int sg_stat[6];
-       struct ub_scsi_trace tr;
 };
 
 /*
@@ -460,137 +423,6 @@ static int ub_qlock_next = 0;
 static DEFINE_SPINLOCK(ub_lock);       /* Locks globals and ->openc */
 
 /*
- * The SCSI command tracing procedures.
- */
-
-static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       int n;
-       struct ub_scsi_cmd_trace *t;
-
-       if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0;
-       t = &sc->tr.vec[n];
-
-       memset(t, 0, sizeof(struct ub_scsi_cmd_trace));
-       t->tag = cmd->tag;
-       t->op = cmd->cdb[0];
-       t->dir = cmd->dir;
-       t->req_size = cmd->len;
-       t->st_hst[0] = cmd->state;
-
-       sc->tr.cur = n;
-       cmd->trace_index = n;
-}
-
-static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       int n;
-       struct ub_scsi_cmd_trace *t;
-
-       t = &sc->tr.vec[cmd->trace_index];
-       if (t->tag == cmd->tag) {
-               if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0;
-               t->st_hst[n] = cmd->state;
-               t->hcur = n;
-       }
-}
-
-static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct ub_scsi_cmd_trace *t;
-
-       t = &sc->tr.vec[cmd->trace_index];
-       if (t->tag == cmd->tag)
-               t->act_size = cmd->act_len;
-}
-
-static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    unsigned char *sense)
-{
-       struct ub_scsi_cmd_trace *t;
-
-       t = &sc->tr.vec[cmd->trace_index];
-       if (t->tag == cmd->tag) {
-               t->key = sense[2] & 0x0F;
-               t->asc = sense[12];
-               t->ascq = sense[13];
-       }
-}
-
-static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
-    char *page)
-{
-       struct usb_interface *intf;
-       struct ub_dev *sc;
-       struct list_head *p;
-       struct ub_lun *lun;
-       int cnt;
-       unsigned long flags;
-       int nc, nh;
-       int i, j;
-       struct ub_scsi_cmd_trace *t;
-
-       intf = to_usb_interface(dev);
-       sc = usb_get_intfdata(intf);
-       if (sc == NULL)
-               return 0;
-
-       cnt = 0;
-       spin_lock_irqsave(sc->lock, flags);
-
-       cnt += sprintf(page + cnt,
-           "poison %d reset %d\n",
-           atomic_read(&sc->poison), sc->reset);
-       cnt += sprintf(page + cnt,
-           "qlen %d qmax %d\n",
-           sc->cmd_queue.qlen, sc->cmd_queue.qmax);
-       cnt += sprintf(page + cnt,
-           "sg %d %d %d %d %d .. %d\n",
-           sc->sg_stat[0],
-           sc->sg_stat[1],
-           sc->sg_stat[2],
-           sc->sg_stat[3],
-           sc->sg_stat[4],
-           sc->sg_stat[5]);
-
-       list_for_each (p, &sc->luns) {
-               lun = list_entry(p, struct ub_lun, link);
-               cnt += sprintf(page + cnt,
-                   "lun %u changed %d removable %d readonly %d\n",
-                   lun->num, lun->changed, lun->removable, lun->readonly);
-       }
-
-       if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
-       for (j = 0; j < SCMD_TRACE_SZ; j++) {
-               t = &sc->tr.vec[nc];
-
-               cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op);
-               if (t->op == REQUEST_SENSE) {
-                       cnt += sprintf(page + cnt, " [sense %x %02x %02x]",
-                                       t->key, t->asc, t->ascq);
-               } else {
-                       cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir));
-                       cnt += sprintf(page + cnt, " [%5d %5d]",
-                                       t->req_size, t->act_size);
-               }
-               if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0;
-               for (i = 0; i < SCMD_ST_HIST_SZ; i++) {
-                       cnt += sprintf(page + cnt, " %s",
-                                       ub_scsi_cmd_stname[(int)t->st_hst[nh]]);
-                       if (++nh == SCMD_ST_HIST_SZ) nh = 0;
-               }
-               cnt += sprintf(page + cnt, "\n");
-
-               if (++nc == SCMD_TRACE_SZ) nc = 0;
-       }
-
-       spin_unlock_irqrestore(sc->lock, flags);
-       return cnt;
-}
-
-static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */
-
-/*
  * The id allocator.
  *
  * This also stores the host for indexing by minor, which is somewhat dirty.
@@ -1092,7 +924,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        add_timer(&sc->work_timer);
 
        cmd->state = UB_CMDST_CMD;
-       ub_cmdtr_state(sc, cmd);
        return 0;
 }
 
@@ -1145,12 +976,10 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
                        ub_cmdq_pop(sc);
                        (*cmd->done)(sc, cmd);
                } else if (cmd->state == UB_CMDST_INIT) {
-                       ub_cmdtr_new(sc, cmd);
                        if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
                                break;
                        cmd->error = rc;
                        cmd->state = UB_CMDST_DONE;
-                       ub_cmdtr_state(sc, cmd);
                } else {
                        if (!ub_is_completed(&sc->work_done))
                                break;
@@ -1247,7 +1076,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                                return;
                        }
                        cmd->state = UB_CMDST_CLEAR;
-                       ub_cmdtr_state(sc, cmd);
                        return;
                case -ESHUTDOWN:        /* unplug */
                case -EILSEQ:           /* unplug timeout on uhci */
@@ -1279,7 +1107,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                                return;
                        }
                        cmd->state = UB_CMDST_CLR2STS;
-                       ub_cmdtr_state(sc, cmd);
                        return;
                }
                if (urb->status == -EOVERFLOW) {
@@ -1304,7 +1131,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        if (urb->status != 0 ||
                            len != cmd->sgv[cmd->current_sg].length) {
                                cmd->act_len += len;
-                               ub_cmdtr_act_len(sc, cmd);
 
                                cmd->error = -EIO;
                                ub_state_stat(sc, cmd);
@@ -1331,7 +1157,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                }
 
                cmd->act_len += urb->actual_length;
-               ub_cmdtr_act_len(sc, cmd);
 
                if (++cmd->current_sg < cmd->nsg) {
                        ub_data_start(sc, cmd);
@@ -1357,7 +1182,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        cmd->error = -EIO;              /* A cheap trick... */
 
                        cmd->state = UB_CMDST_CLRRS;
-                       ub_cmdtr_state(sc, cmd);
                        return;
                }
 
@@ -1441,7 +1265,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        return;
                }
                cmd->state = UB_CMDST_DONE;
-               ub_cmdtr_state(sc, cmd);
                ub_cmdq_pop(sc);
                (*cmd->done)(sc, cmd);
 
@@ -1496,7 +1319,6 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        add_timer(&sc->work_timer);
 
        cmd->state = UB_CMDST_DATA;
-       ub_cmdtr_state(sc, cmd);
 }
 
 /*
@@ -1508,7 +1330,6 @@ static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc)
 
        cmd->error = rc;
        cmd->state = UB_CMDST_DONE;
-       ub_cmdtr_state(sc, cmd);
        ub_cmdq_pop(sc);
        (*cmd->done)(sc, cmd);
 }
@@ -1554,7 +1375,6 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 
        cmd->stat_count = 0;
        cmd->state = UB_CMDST_STAT;
-       ub_cmdtr_state(sc, cmd);
 }
 
 /*
@@ -1573,7 +1393,6 @@ static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                return;
 
        cmd->state = UB_CMDST_STAT;
-       ub_cmdtr_state(sc, cmd);
 }
 
 /*
@@ -1611,7 +1430,6 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        scmd->tag = sc->tagcnt++;
 
        cmd->state = UB_CMDST_SENSE;
-       ub_cmdtr_state(sc, cmd);
 
        ub_cmdq_insert(sc, scmd);
        return;
@@ -1668,11 +1486,6 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
        struct ub_scsi_cmd *cmd;
 
        /*
-        * Ignoring scmd->act_len, because the buffer was pre-zeroed.
-        */
-       ub_cmdtr_sense(sc, scmd, sense);
-
-       /*
         * Find the command which triggered the unit attention or a check,
         * save the sense into it, and advance its state machine.
         */
@@ -1693,6 +1506,9 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
                return;
        }
 
+       /*
+        * Ignoring scmd->act_len, because the buffer was pre-zeroed.
+        */
        cmd->key = sense[2] & 0x0F;
        cmd->asc = sense[12];
        cmd->ascq = sense[13];
@@ -1849,26 +1665,6 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
        sc->openc++;
        spin_unlock_irqrestore(&ub_lock, flags);
 
-       /*
-        * This is a workaround for a specific problem in our block layer.
-        * In 2.6.9, register_disk duplicates the code from rescan_partitions.
-        * However, if we do add_disk with a device which persistently reports
-        * a changed media, add_disk calls register_disk, which does do_open,
-        * which will call rescan_paritions for changed media. After that,
-        * register_disk attempts to do it all again and causes double kobject
-        * registration and a eventually an oops on module removal.
-        *
-        * The bottom line is, Al Viro says that we should not allow
-        * bdev->bd_invalidated to be set when doing add_disk no matter what.
-        */
-       if (lun->first_open) {
-               lun->first_open = 0;
-               if (lun->changed) {
-                       rc = -ENOMEDIUM;
-                       goto err_open;
-               }
-       }
-
        if (lun->removable || lun->readonly)
                check_disk_change(inode->i_bdev);
 
@@ -2007,9 +1803,8 @@ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
        init_completion(&compl);
 
        rc = -ENOMEM;
-       if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+       if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
                goto err_alloc;
-       memset(cmd, 0, ALLOC_SIZE);
 
        cmd->cdb[0] = TEST_UNIT_READY;
        cmd->cdb_len = 6;
@@ -2062,9 +1857,8 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
        init_completion(&compl);
 
        rc = -ENOMEM;
-       if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+       if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
                goto err_alloc;
-       memset(cmd, 0, ALLOC_SIZE);
        p = (char *)cmd + sizeof(struct ub_scsi_cmd);
 
        cmd->cdb[0] = 0x25;
@@ -2405,9 +2199,8 @@ static int ub_probe(struct usb_interface *intf,
                return -ENXIO;
 
        rc = -ENOMEM;
-       if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
+       if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
                goto err_core;
-       memset(sc, 0, sizeof(struct ub_dev));
        sc->lock = ub_next_lock();
        INIT_LIST_HEAD(&sc->luns);
        usb_init_urb(&sc->work_urb);
@@ -2438,9 +2231,6 @@ static int ub_probe(struct usb_interface *intf,
        if (ub_get_pipes(sc, sc->dev, intf) != 0)
                goto err_dev_desc;
 
-       if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0)
-               goto err_diag;
-
        /*
         * At this point, all USB initialization is done, do upper layer.
         * We really hate halfway initialized structures, so from the
@@ -2480,19 +2270,8 @@ static int ub_probe(struct usb_interface *intf,
 
        nluns = 1;
        for (i = 0; i < 3; i++) {
-               if ((rc = ub_sync_getmaxlun(sc)) < 0) {
-                       /* 
-                        * This segment is taken from usb-storage. They say
-                        * that ZIP-100 needs this, but my own ZIP-100 works
-                        * fine without this.
-                        * Still, it does not seem to hurt anything.
-                        */
-                       if (rc == -EPIPE) {
-                               ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
-                               ub_probe_clear_stall(sc, sc->send_bulk_pipe);
-                       }
+               if ((rc = ub_sync_getmaxlun(sc)) < 0)
                        break;
-               }
                if (rc != 0) {
                        nluns = rc;
                        break;
@@ -2505,8 +2284,6 @@ static int ub_probe(struct usb_interface *intf,
        }
        return 0;
 
-       /* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
-err_diag:
 err_dev_desc:
        usb_set_intfdata(intf, NULL);
        // usb_put_intf(sc->intf);
@@ -2524,9 +2301,8 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        int rc;
 
        rc = -ENOMEM;
-       if ((lun = kmalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
+       if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
                goto err_alloc;
-       memset(lun, 0, sizeof(struct ub_lun));
        lun->num = lnum;
 
        rc = -ENOSR;
@@ -2541,7 +2317,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
 
        lun->removable = 1;             /* XXX Query this from the device */
        lun->changed = 1;               /* ub_revalidate clears only */
-       lun->first_open = 1;
        ub_revalidate(sc, lun);
 
        rc = -ENOMEM;
@@ -2636,7 +2411,6 @@ static void ub_disconnect(struct usb_interface *intf)
                while ((cmd = ub_cmdq_peek(sc)) != NULL) {
                        cmd->error = -ENOTCONN;
                        cmd->state = UB_CMDST_DONE;
-                       ub_cmdtr_state(sc, cmd);
                        ub_cmdq_pop(sc);
                        (*cmd->done)(sc, cmd);
                        cnt++;
@@ -2687,7 +2461,6 @@ static void ub_disconnect(struct usb_interface *intf)
         * and no URBs left in transit.
         */
 
-       device_remove_file(&sc->intf->dev, &dev_attr_diag);
        usb_set_intfdata(intf, NULL);
        // usb_put_intf(sc->intf);
        sc->intf = NULL;
index 503dd90..090d154 100644 (file)
@@ -31,7 +31,7 @@ obj-$(CONFIG_MOXA_INTELLIO)   += moxa.o
 obj-$(CONFIG_A2232)            += ser_a2232.o generic_serial.o
 obj-$(CONFIG_ATARI_DSP56K)     += dsp56k.o
 obj-$(CONFIG_MOXA_SMARTIO)     += mxser.o
-obj-$(CONFIG_COMPUTONE)                += ip2.o ip2main.o
+obj-$(CONFIG_COMPUTONE)                += ip2/
 obj-$(CONFIG_RISCOM8)          += riscom8.o
 obj-$(CONFIG_ISI)              += isicom.o
 obj-$(CONFIG_SYNCLINK)         += synclink.o
index 56ace9d..5278c38 100644 (file)
@@ -37,8 +37,8 @@ config DRM_RADEON
        help
          Choose this option if you have an ATI Radeon graphics card.  There
          are both PCI and AGP versions.  You don't need to choose this to
-         run the Radeon in plain VGA mode.  There is a product page at
-         <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
+         run the Radeon in plain VGA mode.
+         
          If M is selected, the module will be called radeon.
 
 config DRM_I810
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile
new file mode 100644 (file)
index 0000000..6bfe254
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the Computone IntelliPort Plus Driver
+#
+
+obj-$(CONFIG_COMPUTONE)         += ip2.o ip2main.o
+
+ip2-objs                       := ip2base.o
+
similarity index 95%
rename from drivers/char/ip2.c
rename to drivers/char/ip2/ip2base.c
index 7cadfc6..435ccfc 100644 (file)
 #define __initdata
 #endif
 
-#include "./ip2/ip2types.h"            
-#include "./ip2/fip_firm.h"            // the meat
+#include "ip2types.h"          
+#include "fip_firm.h"          // the meat
 
 int
 ip2_loadmain(int *, int  *, unsigned char *, int ); // ref into ip2main.c
 
 /* Note: Add compiled in defaults to these arrays, not to the structure
-       in ip2/ip2.h any longer.  That structure WILL get overridden
+       in ip2.h any longer.  That structure WILL get overridden
        by these values, or command line values, or insmod values!!!  =mhw=
 */
 static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 };
similarity index 99%
rename from drivers/char/ip2main.c
rename to drivers/char/ip2/ip2main.c
index 48fcfba..03db1cb 100644 (file)
@@ -35,7 +35,7 @@
 // Clean up potential NULL pointer dereferences
 // Clean up devfs registration
 // Add kernel command line parsing for io and irq
-//     Compile defaults for io and irq are now set in ip2.c not ip2/ip2.h!
+//     Compile defaults for io and irq are now set in ip2.c not ip2.h!
 // Reworked poll_only hack for explicit parameter setting
 //     You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
 // Merged ip2_loadmain and old_ip2_init
 
 #include <asm/uaccess.h>
 
-#include "./ip2/ip2types.h"
-#include "./ip2/ip2trace.h"
-#include "./ip2/ip2ioctl.h"
-#include "./ip2/ip2.h"
-#include "./ip2/i2ellis.h"
-#include "./ip2/i2lib.h"
+#include "ip2types.h"
+#include "ip2trace.h"
+#include "ip2ioctl.h"
+#include "ip2.h"
+#include "i2ellis.h"
+#include "i2lib.h"
 
 /*****************
  * /proc/ip2mem  *
@@ -282,9 +282,9 @@ static int tracewrap;
 /* Code */
 /********/
 
-#include "./ip2/i2ellis.c"    /* Extremely low-level interface services */
-#include "./ip2/i2cmd.c"      /* Standard loadware command definitions */
-#include "./ip2/i2lib.c"      /* High level interface services */
+#include "i2ellis.c"    /* Extremely low-level interface services */
+#include "i2cmd.c"      /* Standard loadware command definitions */
+#include "i2lib.c"      /* High level interface services */
 
 /* Configuration area for modprobe */
 
index 2e30865..b0038b1 100644 (file)
@@ -448,13 +448,13 @@ static int s3c2410_rtc_probe(struct platform_device *pdev)
        /* find the IRQs */
 
        s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
-       if (s3c2410_rtc_tickno <= 0) {
+       if (s3c2410_rtc_tickno < 0) {
                dev_err(&pdev->dev, "no irq for rtc tick\n");
                return -ENOENT;
        }
 
        s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
-       if (s3c2410_rtc_alarmno <= 0) {
+       if (s3c2410_rtc_alarmno < 0) {
                dev_err(&pdev->dev, "no irq for alarm\n");
                return -ENOENT;
        }
index b4d8434..2c2c517 100644 (file)
@@ -338,6 +338,10 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
 
        wdt->dev = &dev->dev;
        wdt->irq = platform_get_irq(dev, 0);
+       if (wdt->irq < 0) {
+               ret = -ENXIO;
+               goto err_free;
+       }
        wdt->base = ioremap(res->start, res->end - res->start + 1);
        if (!wdt->base) {
                ret = -ENOMEM;
index 505677f..d7125f4 100644 (file)
@@ -97,6 +97,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
                group = __group;
        }
 
+       if (!netlink_has_listeners(dev->nls, group))
+               return -ESRCH;
+
        size = NLMSG_SPACE(sizeof(*msg) + msg->len);
 
        skb = alloc_skb(size, gfp_mask);
@@ -111,9 +114,7 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
 
        NETLINK_CB(skb).dst_group = group;
 
-       netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
-
-       return 0;
+       return netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
 
 nlmsg_failure:
        kfree_skb(skb);
index 1414851..d00a02f 100644 (file)
@@ -434,7 +434,7 @@ static int
 iop3xx_i2c_probe(struct platform_device *pdev)
 {
        struct resource *res;
-       int ret;
+       int ret, irq;
        struct i2c_adapter *new_adapter;
        struct i2c_algo_iop3xx_data *adapter_data;
 
@@ -470,7 +470,12 @@ iop3xx_i2c_probe(struct platform_device *pdev)
                goto release_region;
        }
 
-       ret = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0,
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = -ENXIO;
+               goto unmap;
+       }
+       ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
                                pdev->name, adapter_data);
 
        if (ret) {
index 5ccd338..2721e4c 100644 (file)
@@ -302,6 +302,10 @@ static int fsl_i2c_probe(struct platform_device *pdev)
        }
 
        i2c->irq = platform_get_irq(pdev, 0);
+       if (i2c->irq < 0) {
+               result = -ENXIO;
+               goto fail_get_irq;
+       }
        i2c->flags = pdata->device_flags;
        init_waitqueue_head(&i2c->queue);
 
@@ -340,6 +344,7 @@ static int fsl_i2c_probe(struct platform_device *pdev)
       fail_irq:
        iounmap(i2c->base);
       fail_map:
+      fail_get_irq:
        kfree(i2c);
        return result;
 };
index 22781d8..ac5cde1 100644 (file)
@@ -516,6 +516,10 @@ mv64xxx_i2c_probe(struct platform_device *pd)
        drv_data->freq_m = pdata->freq_m;
        drv_data->freq_n = pdata->freq_n;
        drv_data->irq = platform_get_irq(pd, 0);
+       if (drv_data->irq < 0) {
+               rc = -ENXIO;
+               goto exit_unmap_regs;
+       }
        drv_data->adapter.id = I2C_HW_MV64XXX;
        drv_data->adapter.algo = &mv64xxx_i2c_algo;
        drv_data->adapter.owner = THIS_MODULE;
index 32431dc..71f27e9 100644 (file)
@@ -674,6 +674,11 @@ static int au_ide_probe(struct device *dev)
                ret = -ENODEV;
                goto out;
        }
+       if (ahwif->irq < 0) {
+               pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id);
+               ret = -ENODEV;
+               goto out;
+       }
 
        if (!request_mem_region (res->start, res->end-res->start, pdev->name)) {
                pr_debug("%s: request_mem_region failed\n", DRV_NAME);
index 34b724a..ecd1a30 100644 (file)
@@ -78,25 +78,6 @@ ib_get_agent_port(struct ib_device *device, int port_num)
        return entry;
 }
 
-int smi_check_local_dr_smp(struct ib_smp *smp,
-                          struct ib_device *device,
-                          int port_num)
-{
-       struct ib_agent_port_private *port_priv;
-
-       if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
-               return 1;
-
-       port_priv = ib_get_agent_port(device, port_num);
-       if (!port_priv) {
-               printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d "
-                      "not open\n", device->name, port_num);
-               return 1;
-       }
-
-       return smi_check_local_smp(port_priv->agent[0], smp);
-}
-
 int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
                        struct ib_wc *wc, struct ib_device *device,
                        int port_num, int qpn)
index 2514de3..7cfedb8 100644 (file)
@@ -121,7 +121,7 @@ struct cm_id_private {
 
        struct rb_node service_node;
        struct rb_node sidr_id_node;
-       spinlock_t lock;
+       spinlock_t lock;        /* Do not acquire inside cm.lock */
        wait_queue_head_t wait;
        atomic_t refcount;
 
@@ -1547,40 +1547,46 @@ static int cm_rep_handler(struct cm_work *work)
                return -EINVAL;
        }
 
+       cm_format_rep_event(work);
+
+       spin_lock_irqsave(&cm_id_priv->lock, flags);
+       switch (cm_id_priv->id.state) {
+       case IB_CM_REQ_SENT:
+       case IB_CM_MRA_REQ_RCVD:
+               break;
+       default:
+               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+               ret = -EINVAL;
+               goto error;
+       }
+
        cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id;
        cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid;
        cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg);
 
-       spin_lock_irqsave(&cm.lock, flags);
+       spin_lock(&cm.lock);
        /* Check for duplicate REP. */
        if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
-               spin_unlock_irqrestore(&cm.lock, flags);
+               spin_unlock(&cm.lock);
+               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                ret = -EINVAL;
                goto error;
        }
        /* Check for a stale connection. */
        if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) {
-               spin_unlock_irqrestore(&cm.lock, flags);
+               rb_erase(&cm_id_priv->timewait_info->remote_id_node,
+                        &cm.remote_id_table);
+               cm_id_priv->timewait_info->inserted_remote_id = 0;
+               spin_unlock(&cm.lock);
+               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
                cm_issue_rej(work->port, work->mad_recv_wc,
                             IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP,
                             NULL, 0);
                ret = -EINVAL;
                goto error;
        }
-       spin_unlock_irqrestore(&cm.lock, flags);
-
-       cm_format_rep_event(work);
+       spin_unlock(&cm.lock);
 
-       spin_lock_irqsave(&cm_id_priv->lock, flags);
-       switch (cm_id_priv->id.state) {
-       case IB_CM_REQ_SENT:
-       case IB_CM_MRA_REQ_RCVD:
-               break;
-       default:
-               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               ret = -EINVAL;
-               goto error;
-       }
        cm_id_priv->id.state = IB_CM_REP_RCVD;
        cm_id_priv->id.remote_id = rep_msg->local_comm_id;
        cm_id_priv->remote_qpn = cm_rep_get_local_qpn(rep_msg);
@@ -1603,7 +1609,7 @@ static int cm_rep_handler(struct cm_work *work)
                cm_deref_id(cm_id_priv);
        return 0;
 
-error: cm_cleanup_timewait(cm_id_priv->timewait_info);
+error:
        cm_deref_id(cm_id_priv);
        return ret;
 }
index d34a6f1..838bf54 100644 (file)
@@ -278,9 +278,9 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd             *pd,
        {
                struct ib_pool_fmr *fmr;
                struct ib_fmr_attr attr = {
-                       .max_pages = params->max_pages_per_fmr,
-                       .max_maps  = IB_FMR_MAX_REMAPS,
-                       .page_size = PAGE_SHIFT
+                       .max_pages  = params->max_pages_per_fmr,
+                       .max_maps   = IB_FMR_MAX_REMAPS,
+                       .page_shift = params->page_shift
                };
 
                for (i = 0; i < params->pool_size; ++i) {
index c82f47a..f7854b6 100644 (file)
@@ -31,7 +31,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: mad.c 2817 2005-07-07 11:29:26Z halr $
+ * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 #include <linux/dma-mapping.h>
 
@@ -679,8 +679,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
                goto out;
        }
        /* Check to post send on QP or process locally */
-       ret = smi_check_local_dr_smp(smp, device, port_num);
-       if (!ret || !device->process_mad)
+       ret = smi_check_local_smp(smp, device);
+       if (!ret)
                goto out;
 
        local = kmalloc(sizeof *local, GFP_ATOMIC);
@@ -765,18 +765,67 @@ out:
        return ret;
 }
 
-static int get_buf_length(int hdr_len, int data_len)
+static int get_pad_size(int hdr_len, int data_len)
 {
        int seg_size, pad;
 
        seg_size = sizeof(struct ib_mad) - hdr_len;
        if (data_len && seg_size) {
                pad = seg_size - data_len % seg_size;
-               if (pad == seg_size)
-                       pad = 0;
+               return pad == seg_size ? 0 : pad;
        } else
-               pad = seg_size;
-       return hdr_len + data_len + pad;
+               return seg_size;
+}
+
+static void free_send_rmpp_list(struct ib_mad_send_wr_private *mad_send_wr)
+{
+       struct ib_rmpp_segment *s, *t;
+
+       list_for_each_entry_safe(s, t, &mad_send_wr->rmpp_list, list) {
+               list_del(&s->list);
+               kfree(s);
+       }
+}
+
+static int alloc_send_rmpp_list(struct ib_mad_send_wr_private *send_wr,
+                               gfp_t gfp_mask)
+{
+       struct ib_mad_send_buf *send_buf = &send_wr->send_buf;
+       struct ib_rmpp_mad *rmpp_mad = send_buf->mad;
+       struct ib_rmpp_segment *seg = NULL;
+       int left, seg_size, pad;
+
+       send_buf->seg_size = sizeof (struct ib_mad) - send_buf->hdr_len;
+       seg_size = send_buf->seg_size;
+       pad = send_wr->pad;
+
+       /* Allocate data segments. */
+       for (left = send_buf->data_len + pad; left > 0; left -= seg_size) {
+               seg = kmalloc(sizeof (*seg) + seg_size, gfp_mask);
+               if (!seg) {
+                       printk(KERN_ERR "alloc_send_rmpp_segs: RMPP mem "
+                              "alloc failed for len %zd, gfp %#x\n",
+                              sizeof (*seg) + seg_size, gfp_mask);
+                       free_send_rmpp_list(send_wr);
+                       return -ENOMEM;
+               }
+               seg->num = ++send_buf->seg_count;
+               list_add_tail(&seg->list, &send_wr->rmpp_list);
+       }
+
+       /* Zero any padding */
+       if (pad)
+               memset(seg->data + seg_size - pad, 0, pad);
+
+       rmpp_mad->rmpp_hdr.rmpp_version = send_wr->mad_agent_priv->
+                                         agent.rmpp_version;
+       rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA;
+       ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
+
+       send_wr->cur_seg = container_of(send_wr->rmpp_list.next,
+                                       struct ib_rmpp_segment, list);
+       send_wr->last_ack_seg = send_wr->cur_seg;
+       return 0;
 }
 
 struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
@@ -787,32 +836,40 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
 {
        struct ib_mad_agent_private *mad_agent_priv;
        struct ib_mad_send_wr_private *mad_send_wr;
-       int buf_size;
+       int pad, message_size, ret, size;
        void *buf;
 
        mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private,
                                      agent);
-       buf_size = get_buf_length(hdr_len, data_len);
+       pad = get_pad_size(hdr_len, data_len);
+       message_size = hdr_len + data_len + pad;
 
        if ((!mad_agent->rmpp_version &&
-            (rmpp_active || buf_size > sizeof(struct ib_mad))) ||
-           (!rmpp_active && buf_size > sizeof(struct ib_mad)))
+            (rmpp_active || message_size > sizeof(struct ib_mad))) ||
+           (!rmpp_active && message_size > sizeof(struct ib_mad)))
                return ERR_PTR(-EINVAL);
 
-       buf = kzalloc(sizeof *mad_send_wr + buf_size, gfp_mask);
+       size = rmpp_active ? hdr_len : sizeof(struct ib_mad);
+       buf = kzalloc(sizeof *mad_send_wr + size, gfp_mask);
        if (!buf)
                return ERR_PTR(-ENOMEM);
 
-       mad_send_wr = buf + buf_size;
+       mad_send_wr = buf + size;
+       INIT_LIST_HEAD(&mad_send_wr->rmpp_list);
        mad_send_wr->send_buf.mad = buf;
+       mad_send_wr->send_buf.hdr_len = hdr_len;
+       mad_send_wr->send_buf.data_len = data_len;
+       mad_send_wr->pad = pad;
 
        mad_send_wr->mad_agent_priv = mad_agent_priv;
-       mad_send_wr->sg_list[0].length = buf_size;
+       mad_send_wr->sg_list[0].length = hdr_len;
        mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey;
+       mad_send_wr->sg_list[1].length = sizeof(struct ib_mad) - hdr_len;
+       mad_send_wr->sg_list[1].lkey = mad_agent->mr->lkey;
 
        mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr;
        mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list;
-       mad_send_wr->send_wr.num_sge = 1;
+       mad_send_wr->send_wr.num_sge = 2;
        mad_send_wr->send_wr.opcode = IB_WR_SEND;
        mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED;
        mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn;
@@ -820,13 +877,11 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
        mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index;
 
        if (rmpp_active) {
-               struct ib_rmpp_mad *rmpp_mad = mad_send_wr->send_buf.mad;
-               rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(hdr_len -
-                                                  IB_MGMT_RMPP_HDR + data_len);
-               rmpp_mad->rmpp_hdr.rmpp_version = mad_agent->rmpp_version;
-               rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA;
-               ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr,
-                                 IB_MGMT_RMPP_FLAG_ACTIVE);
+               ret = alloc_send_rmpp_list(mad_send_wr, gfp_mask);
+               if (ret) {
+                       kfree(buf);
+                       return ERR_PTR(ret);
+               }
        }
 
        mad_send_wr->send_buf.mad_agent = mad_agent;
@@ -835,14 +890,50 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
 }
 EXPORT_SYMBOL(ib_create_send_mad);
 
+void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num)
+{
+       struct ib_mad_send_wr_private *mad_send_wr;
+       struct list_head *list;
+
+       mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private,
+                                  send_buf);
+       list = &mad_send_wr->cur_seg->list;
+
+       if (mad_send_wr->cur_seg->num < seg_num) {
+               list_for_each_entry(mad_send_wr->cur_seg, list, list)
+                       if (mad_send_wr->cur_seg->num == seg_num)
+                               break;
+       } else if (mad_send_wr->cur_seg->num > seg_num) {
+               list_for_each_entry_reverse(mad_send_wr->cur_seg, list, list)
+                       if (mad_send_wr->cur_seg->num == seg_num)
+                               break;
+       }
+       return mad_send_wr->cur_seg->data;
+}
+EXPORT_SYMBOL(ib_get_rmpp_segment);
+
+static inline void *ib_get_payload(struct ib_mad_send_wr_private *mad_send_wr)
+{
+       if (mad_send_wr->send_buf.seg_count)
+               return ib_get_rmpp_segment(&mad_send_wr->send_buf,
+                                          mad_send_wr->seg_num);
+       else
+               return mad_send_wr->send_buf.mad +
+                      mad_send_wr->send_buf.hdr_len;
+}
+
 void ib_free_send_mad(struct ib_mad_send_buf *send_buf)
 {
        struct ib_mad_agent_private *mad_agent_priv;
+       struct ib_mad_send_wr_private *mad_send_wr;
 
        mad_agent_priv = container_of(send_buf->mad_agent,
                                      struct ib_mad_agent_private, agent);
-       kfree(send_buf->mad);
+       mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private,
+                                  send_buf);
 
+       free_send_rmpp_list(mad_send_wr);
+       kfree(send_buf->mad);
        if (atomic_dec_and_test(&mad_agent_priv->refcount))
                wake_up(&mad_agent_priv->wait);
 }
@@ -865,10 +956,17 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
 
        mad_agent = mad_send_wr->send_buf.mad_agent;
        sge = mad_send_wr->sg_list;
-       sge->addr = dma_map_single(mad_agent->device->dma_device,
-                                  mad_send_wr->send_buf.mad, sge->length,
-                                  DMA_TO_DEVICE);
-       pci_unmap_addr_set(mad_send_wr, mapping, sge->addr);
+       sge[0].addr = dma_map_single(mad_agent->device->dma_device,
+                                    mad_send_wr->send_buf.mad,
+                                    sge[0].length,
+                                    DMA_TO_DEVICE);
+       pci_unmap_addr_set(mad_send_wr, header_mapping, sge[0].addr);
+
+       sge[1].addr = dma_map_single(mad_agent->device->dma_device,
+                                    ib_get_payload(mad_send_wr),
+                                    sge[1].length,
+                                    DMA_TO_DEVICE);
+       pci_unmap_addr_set(mad_send_wr, payload_mapping, sge[1].addr);
 
        spin_lock_irqsave(&qp_info->send_queue.lock, flags);
        if (qp_info->send_queue.count < qp_info->send_queue.max_active) {
@@ -885,11 +983,14 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
                list_add_tail(&mad_send_wr->mad_list.list, list);
        }
        spin_unlock_irqrestore(&qp_info->send_queue.lock, flags);
-       if (ret)
+       if (ret) {
                dma_unmap_single(mad_agent->device->dma_device,
-                                pci_unmap_addr(mad_send_wr, mapping),
-                                sge->length, DMA_TO_DEVICE);
-
+                                pci_unmap_addr(mad_send_wr, header_mapping),
+                                sge[0].length, DMA_TO_DEVICE);
+               dma_unmap_single(mad_agent->device->dma_device,
+                                pci_unmap_addr(mad_send_wr, payload_mapping),
+                                sge[1].length, DMA_TO_DEVICE);
+       }
        return ret;
 }
 
@@ -1661,9 +1762,7 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
                                            port_priv->device->node_type,
                                            port_priv->port_num))
                        goto out;
-               if (!smi_check_local_dr_smp(&recv->mad.smp,
-                                           port_priv->device,
-                                           port_priv->port_num))
+               if (!smi_check_local_smp(&recv->mad.smp, port_priv->device))
                        goto out;
        }
 
@@ -1862,8 +1961,11 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv,
 
 retry:
        dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device,
-                        pci_unmap_addr(mad_send_wr, mapping),
+                        pci_unmap_addr(mad_send_wr, header_mapping),
                         mad_send_wr->sg_list[0].length, DMA_TO_DEVICE);
+       dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device,
+                        pci_unmap_addr(mad_send_wr, payload_mapping),
+                        mad_send_wr->sg_list[1].length, DMA_TO_DEVICE);
        queued_send_wr = NULL;
        spin_lock_irqsave(&send_queue->lock, flags);
        list_del(&mad_list->list);
@@ -2262,8 +2364,12 @@ static void timeout_sends(void *data)
 static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg)
 {
        struct ib_mad_port_private *port_priv = cq->cq_context;
+       unsigned long flags;
 
-       queue_work(port_priv->wq, &port_priv->work);
+       spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+       if (!list_empty(&port_priv->port_list))
+               queue_work(port_priv->wq, &port_priv->work);
+       spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
 }
 
 /*
@@ -2575,18 +2681,23 @@ static int ib_mad_port_open(struct ib_device *device,
        }
        INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv);
 
+       spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+       list_add_tail(&port_priv->port_list, &ib_mad_port_list);
+       spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
+
        ret = ib_mad_port_start(port_priv);
        if (ret) {
                printk(KERN_ERR PFX "Couldn't start port\n");
                goto error9;
        }
 
-       spin_lock_irqsave(&ib_mad_port_list_lock, flags);
-       list_add_tail(&port_priv->port_list, &ib_mad_port_list);
-       spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
        return 0;
 
 error9:
+       spin_lock_irqsave(&ib_mad_port_list_lock, flags);
+       list_del_init(&port_priv->port_list);
+       spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
+
        destroy_workqueue(port_priv->wq);
 error8:
        destroy_mad_qp(&port_priv->qp_info[1]);
@@ -2623,11 +2734,9 @@ static int ib_mad_port_close(struct ib_device *device, int port_num)
                printk(KERN_ERR PFX "Port %d not found\n", port_num);
                return -ENODEV;
        }
-       list_del(&port_priv->port_list);
+       list_del_init(&port_priv->port_list);
        spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
 
-       /* Stop processing completions. */
-       flush_workqueue(port_priv->wq);
        destroy_workqueue(port_priv->wq);
        destroy_mad_qp(&port_priv->qp_info[1]);
        destroy_mad_qp(&port_priv->qp_info[0]);
index 570f786..a7125d4 100644 (file)
@@ -31,7 +31,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: mad_priv.h 2730 2005-06-28 16:43:03Z sean.hefty $
+ * $Id: mad_priv.h 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 
 #ifndef __IB_MAD_PRIV_H__
@@ -85,6 +85,12 @@ struct ib_mad_private {
        } mad;
 } __attribute__ ((packed));
 
+struct ib_rmpp_segment {
+       struct list_head list;
+       u32 num;
+       u8 data[0];
+};
+
 struct ib_mad_agent_private {
        struct list_head agent_list;
        struct ib_mad_agent agent;
@@ -119,7 +125,8 @@ struct ib_mad_send_wr_private {
        struct list_head agent_list;
        struct ib_mad_agent_private *mad_agent_priv;
        struct ib_mad_send_buf send_buf;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
+       DECLARE_PCI_UNMAP_ADDR(header_mapping)
+       DECLARE_PCI_UNMAP_ADDR(payload_mapping)
        struct ib_send_wr send_wr;
        struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
        __be64 tid;
@@ -130,11 +137,12 @@ struct ib_mad_send_wr_private {
        enum ib_wc_status status;
 
        /* RMPP control */
+       struct list_head rmpp_list;
+       struct ib_rmpp_segment *last_ack_seg;
+       struct ib_rmpp_segment *cur_seg;
        int last_ack;
        int seg_num;
        int newwin;
-       int total_seg;
-       int data_offset;
        int pad;
 };
 
index 3249e1d..bacfdd5 100644 (file)
@@ -111,14 +111,14 @@ static int data_offset(u8 mgmt_class)
                return IB_MGMT_RMPP_HDR;
 }
 
-static void format_ack(struct ib_rmpp_mad *ack,
+static void format_ack(struct ib_mad_send_buf *msg,
                       struct ib_rmpp_mad *data,
                       struct mad_rmpp_recv *rmpp_recv)
 {
+       struct ib_rmpp_mad *ack = msg->mad;
        unsigned long flags;
 
-       memcpy(&ack->mad_hdr, &data->mad_hdr,
-              data_offset(data->mad_hdr.mgmt_class));
+       memcpy(ack, &data->mad_hdr, msg->hdr_len);
 
        ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
        ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK;
@@ -135,16 +135,16 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv,
                     struct ib_mad_recv_wc *recv_wc)
 {
        struct ib_mad_send_buf *msg;
-       int ret;
+       int ret, hdr_len;
 
+       hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
        msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
-                                recv_wc->wc->pkey_index, 1, IB_MGMT_RMPP_HDR,
-                                IB_MGMT_RMPP_DATA, GFP_KERNEL);
+                                recv_wc->wc->pkey_index, 1, hdr_len,
+                                0, GFP_KERNEL);
        if (!msg)
                return;
 
-       format_ack(msg->mad, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad,
-                  rmpp_recv);
+       format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv);
        msg->ah = rmpp_recv->ah;
        ret = ib_post_send_mad(msg, NULL);
        if (ret)
@@ -156,16 +156,17 @@ static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent,
 {
        struct ib_mad_send_buf *msg;
        struct ib_ah *ah;
+       int hdr_len;
 
        ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc,
                                  recv_wc->recv_buf.grh, agent->port_num);
        if (IS_ERR(ah))
                return (void *) ah;
 
+       hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
        msg = ib_create_send_mad(agent, recv_wc->wc->src_qp,
                                 recv_wc->wc->pkey_index, 1,
-                                IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA,
-                                GFP_KERNEL);
+                                hdr_len, 0, GFP_KERNEL);
        if (IS_ERR(msg))
                ib_destroy_ah(ah);
        else
@@ -195,8 +196,7 @@ static void nack_recv(struct ib_mad_agent_private *agent,
                return;
 
        rmpp_mad = msg->mad;
-       memcpy(rmpp_mad, recv_wc->recv_buf.mad,
-              data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class));
+       memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);
 
        rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
        rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION;
@@ -433,44 +433,6 @@ static struct ib_mad_recv_wc * complete_rmpp(struct mad_rmpp_recv *rmpp_recv)
        return rmpp_wc;
 }
 
-void ib_coalesce_recv_mad(struct ib_mad_recv_wc *mad_recv_wc, void *buf)
-{
-       struct ib_mad_recv_buf *seg_buf;
-       struct ib_rmpp_mad *rmpp_mad;
-       void *data;
-       int size, len, offset;
-       u8 flags;
-
-       len = mad_recv_wc->mad_len;
-       if (len <= sizeof(struct ib_mad)) {
-               memcpy(buf, mad_recv_wc->recv_buf.mad, len);
-               return;
-       }
-
-       offset = data_offset(mad_recv_wc->recv_buf.mad->mad_hdr.mgmt_class);
-
-       list_for_each_entry(seg_buf, &mad_recv_wc->rmpp_list, list) {
-               rmpp_mad = (struct ib_rmpp_mad *)seg_buf->mad;
-               flags = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr);
-
-               if (flags & IB_MGMT_RMPP_FLAG_FIRST) {
-                       data = rmpp_mad;
-                       size = sizeof(*rmpp_mad);
-               } else {
-                       data = (void *) rmpp_mad + offset;
-                       if (flags & IB_MGMT_RMPP_FLAG_LAST)
-                               size = len;
-                       else
-                               size = sizeof(*rmpp_mad) - offset;
-               }
-
-               memcpy(buf, data, size);
-               len -= size;
-               buf += size;
-       }
-}
-EXPORT_SYMBOL(ib_coalesce_recv_mad);
-
 static struct ib_mad_recv_wc *
 continue_rmpp(struct ib_mad_agent_private *agent,
              struct ib_mad_recv_wc *mad_recv_wc)
@@ -570,50 +532,33 @@ start_rmpp(struct ib_mad_agent_private *agent,
        return mad_recv_wc;
 }
 
-static inline u64 get_seg_addr(struct ib_mad_send_wr_private *mad_send_wr)
-{
-       return mad_send_wr->sg_list[0].addr + mad_send_wr->data_offset +
-              (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset) *
-              (mad_send_wr->seg_num - 1);
-}
-
 static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
 {
        struct ib_rmpp_mad *rmpp_mad;
        int timeout;
-       u32 paylen;
+       u32 paylen = 0;
 
        rmpp_mad = mad_send_wr->send_buf.mad;
        ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
-       rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(mad_send_wr->seg_num);
+       rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(++mad_send_wr->seg_num);
 
        if (mad_send_wr->seg_num == 1) {
                rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST;
-               paylen = mad_send_wr->total_seg * IB_MGMT_RMPP_DATA -
+               paylen = mad_send_wr->send_buf.seg_count * IB_MGMT_RMPP_DATA -
                         mad_send_wr->pad;
-               rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
-               mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad);
-       } else {
-               mad_send_wr->send_wr.num_sge = 2;
-               mad_send_wr->sg_list[0].length = mad_send_wr->data_offset;
-               mad_send_wr->sg_list[1].addr = get_seg_addr(mad_send_wr);
-               mad_send_wr->sg_list[1].length = sizeof(struct ib_rmpp_mad) -
-                                                mad_send_wr->data_offset;
-               mad_send_wr->sg_list[1].lkey = mad_send_wr->sg_list[0].lkey;
-               rmpp_mad->rmpp_hdr.paylen_newwin = 0;
        }
 
-       if (mad_send_wr->seg_num == mad_send_wr->total_seg) {
+       if (mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) {
                rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST;
                paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad;
-               rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
        }
+       rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen);
 
        /* 2 seconds for an ACK until we can find the packet lifetime */
        timeout = mad_send_wr->send_buf.timeout_ms;
        if (!timeout || timeout > 2000)
                mad_send_wr->timeout = msecs_to_jiffies(2000);
-       mad_send_wr->seg_num++;
+
        return ib_send_mad(mad_send_wr);
 }
 
@@ -629,7 +574,7 @@ static void abort_send(struct ib_mad_agent_private *agent, __be64 tid,
        if (!mad_send_wr)
                goto out;       /* Unmatched send */
 
-       if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||
+       if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
            (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
                goto out;       /* Send is already done */
 
@@ -645,6 +590,18 @@ out:
        spin_unlock_irqrestore(&agent->lock, flags);
 }
 
+static inline void adjust_last_ack(struct ib_mad_send_wr_private *wr,
+                                  int seg_num)
+{
+       struct list_head *list;
+
+       wr->last_ack = seg_num;
+       list = &wr->last_ack_seg->list;
+       list_for_each_entry(wr->last_ack_seg, list, list)
+               if (wr->last_ack_seg->num == seg_num)
+                       break;
+}
+
 static void process_rmpp_ack(struct ib_mad_agent_private *agent,
                             struct ib_mad_recv_wc *mad_recv_wc)
 {
@@ -675,11 +632,12 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
        if (!mad_send_wr)
                goto out;       /* Unmatched ACK */
 
-       if ((mad_send_wr->last_ack == mad_send_wr->total_seg) ||
+       if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
            (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
                goto out;       /* Send is already done */
 
-       if (seg_num > mad_send_wr->total_seg || seg_num > mad_send_wr->newwin) {
+       if (seg_num > mad_send_wr->send_buf.seg_count ||
+           seg_num > mad_send_wr->newwin) {
                spin_unlock_irqrestore(&agent->lock, flags);
                abort_send(agent, rmpp_mad->mad_hdr.tid,
                           IB_MGMT_RMPP_STATUS_S2B);
@@ -691,11 +649,11 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
                goto out;       /* Old ACK */
 
        if (seg_num > mad_send_wr->last_ack) {
-               mad_send_wr->last_ack = seg_num;
+               adjust_last_ack(mad_send_wr, seg_num);
                mad_send_wr->retries = mad_send_wr->send_buf.retries;
        }
        mad_send_wr->newwin = newwin;
-       if (mad_send_wr->last_ack == mad_send_wr->total_seg) {
+       if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
                /* If no response is expected, the ACK completes the send */
                if (!mad_send_wr->send_buf.timeout_ms) {
                        struct ib_mad_send_wc wc;
@@ -714,7 +672,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
                                             mad_send_wr->send_buf.timeout_ms);
        } else if (mad_send_wr->refcount == 1 &&
                   mad_send_wr->seg_num < mad_send_wr->newwin &&
-                  mad_send_wr->seg_num <= mad_send_wr->total_seg) {
+                  mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) {
                /* Send failure will just result in a timeout/retry */
                ret = send_next_seg(mad_send_wr);
                if (ret)
@@ -838,31 +796,19 @@ out:
 int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
 {
        struct ib_rmpp_mad *rmpp_mad;
-       int i, total_len, ret;
+       int ret;
 
        rmpp_mad = mad_send_wr->send_buf.mad;
        if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
              IB_MGMT_RMPP_FLAG_ACTIVE))
                return IB_RMPP_RESULT_UNHANDLED;
 
-       if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)
+       if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) {
+               mad_send_wr->seg_num = 1;
                return IB_RMPP_RESULT_INTERNAL;
+       }
 
-       if (mad_send_wr->send_wr.num_sge > 1)
-               return -EINVAL;         /* TODO: support num_sge > 1 */
-
-       mad_send_wr->seg_num = 1;
        mad_send_wr->newwin = 1;
-       mad_send_wr->data_offset = data_offset(rmpp_mad->mad_hdr.mgmt_class);
-
-       total_len = 0;
-       for (i = 0; i < mad_send_wr->send_wr.num_sge; i++)
-               total_len += mad_send_wr->send_wr.sg_list[i].length;
-
-        mad_send_wr->total_seg = (total_len - mad_send_wr->data_offset) /
-                       (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset);
-       mad_send_wr->pad = total_len - IB_MGMT_RMPP_HDR -
-                          be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
 
        /* We need to wait for the final ACK even if there isn't a response */
        mad_send_wr->refcount += (mad_send_wr->timeout == 0);
@@ -893,14 +839,14 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,
        if (!mad_send_wr->timeout)
                return IB_RMPP_RESULT_PROCESSED; /* Response received */
 
-       if (mad_send_wr->last_ack == mad_send_wr->total_seg) {
+       if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
                mad_send_wr->timeout =
                        msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
                return IB_RMPP_RESULT_PROCESSED; /* Send done */
        }
 
-       if (mad_send_wr->seg_num > mad_send_wr->newwin ||
-           mad_send_wr->seg_num > mad_send_wr->total_seg)
+       if (mad_send_wr->seg_num == mad_send_wr->newwin ||
+           mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count)
                return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */
 
        ret = send_next_seg(mad_send_wr);
@@ -921,10 +867,12 @@ int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr)
              IB_MGMT_RMPP_FLAG_ACTIVE))
                return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */
 
-       if (mad_send_wr->last_ack == mad_send_wr->total_seg)
+       if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count)
                return IB_RMPP_RESULT_PROCESSED;
 
-       mad_send_wr->seg_num = mad_send_wr->last_ack + 1;
+       mad_send_wr->seg_num = mad_send_wr->last_ack;
+       mad_send_wr->cur_seg = mad_send_wr->last_ack_seg;
+
        ret = send_next_seg(mad_send_wr);
        if (ret)
                return IB_RMPP_RESULT_PROCESSED;
index 2b3c401..3011bfd 100644 (file)
@@ -49,19 +49,16 @@ extern int smi_check_forward_dr_smp(struct ib_smp *smp);
 extern int smi_handle_dr_smp_send(struct ib_smp *smp,
                                  u8 node_type,
                                  int port_num);
-extern int smi_check_local_dr_smp(struct ib_smp *smp,
-                                 struct ib_device *device,
-                                 int port_num);
 
 /*
  * Return 1 if the SMP should be handled by the local SMA/SM via process_mad
  */
-static inline int smi_check_local_smp(struct ib_mad_agent *mad_agent,
-                                     struct ib_smp *smp)
+static inline int smi_check_local_smp(struct ib_smp *smp,
+                                     struct ib_device *device)
 {
        /* C14-9:3 -- We're at the end of the DR segment of path */
        /* C14-9:4 -- Hop Pointer = Hop Count + 1 -> give to SMA/SM */
-       return ((mad_agent->device->process_mad &&
+       return ((device->process_mad &&
                !ib_get_smp_direction(smp) &&
                (smp->hop_ptr == smp->hop_cnt + 1)));
 }
index 5982d68..15121cb 100644 (file)
@@ -112,7 +112,7 @@ static ssize_t state_show(struct ib_port *p, struct port_attribute *unused,
                return ret;
 
        return sprintf(buf, "%d: %s\n", attr.state,
-                      attr.state >= 0 && attr.state <= ARRAY_SIZE(state_name) ?
+                      attr.state >= 0 && attr.state < ARRAY_SIZE(state_name) ?
                       state_name[attr.state] : "UNKNOWN");
 }
 
@@ -472,8 +472,10 @@ alloc_group_attrs(ssize_t (*show)(struct ib_port *,
                        goto err;
 
                if (snprintf(element->name, sizeof(element->name),
-                            "%d", i) >= sizeof(element->name))
+                            "%d", i) >= sizeof(element->name)) {
+                       kfree(element);
                        goto err;
+               }
 
                element->attr.attr.name  = element->name;
                element->attr.attr.mode  = S_IRUGO;
@@ -628,14 +630,42 @@ static ssize_t show_node_guid(struct class_device *cdev, char *buf)
                       be16_to_cpu(((__be16 *) &dev->node_guid)[3]));
 }
 
+static ssize_t show_node_desc(struct class_device *cdev, char *buf)
+{
+       struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
+
+       return sprintf(buf, "%.64s\n", dev->node_desc);
+}
+
+static ssize_t set_node_desc(struct class_device *cdev, const char *buf,
+                             size_t count)
+{
+       struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
+       struct ib_device_modify desc = {};
+       int ret;
+
+       if (!dev->modify_device)
+               return -EIO;
+
+       memcpy(desc.node_desc, buf, min_t(int, count, 64));
+       ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
 static CLASS_DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
 static CLASS_DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL);
 static CLASS_DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL);
+static CLASS_DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc,
+                        set_node_desc);
 
 static struct class_device_attribute *ib_class_attributes[] = {
        &class_device_attr_node_type,
        &class_device_attr_sys_image_guid,
-       &class_device_attr_node_guid
+       &class_device_attr_node_guid,
+       &class_device_attr_node_desc
 };
 
 static struct class ib_class = {
index c908de8..fb6cd42 100644 (file)
@@ -31,7 +31,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: user_mad.c 4010 2005-11-09 23:11:56Z roland $
+ * $Id: user_mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 
 #include <linux/module.h>
@@ -121,6 +121,7 @@ struct ib_umad_file {
 
 struct ib_umad_packet {
        struct ib_mad_send_buf *msg;
+       struct ib_mad_recv_wc  *recv_wc;
        struct list_head   list;
        int                length;
        struct ib_user_mad mad;
@@ -176,31 +177,32 @@ static int queue_packet(struct ib_umad_file *file,
        return ret;
 }
 
+static int data_offset(u8 mgmt_class)
+{
+       if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
+               return IB_MGMT_SA_HDR;
+       else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
+                (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
+               return IB_MGMT_VENDOR_HDR;
+       else
+               return IB_MGMT_RMPP_HDR;
+}
+
 static void send_handler(struct ib_mad_agent *agent,
                         struct ib_mad_send_wc *send_wc)
 {
        struct ib_umad_file *file = agent->context;
-       struct ib_umad_packet *timeout;
        struct ib_umad_packet *packet = send_wc->send_buf->context[0];
 
        ib_destroy_ah(packet->msg->ah);
        ib_free_send_mad(packet->msg);
 
        if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) {
-               timeout = kzalloc(sizeof *timeout + IB_MGMT_MAD_HDR, GFP_KERNEL);
-               if (!timeout)
-                       goto out;
-
-               timeout->length         = IB_MGMT_MAD_HDR;
-               timeout->mad.hdr.id     = packet->mad.hdr.id;
-               timeout->mad.hdr.status = ETIMEDOUT;
-               memcpy(timeout->mad.data, packet->mad.data,
-                      sizeof (struct ib_mad_hdr));
-
-               if (queue_packet(file, agent, timeout))
-                       kfree(timeout);
+               packet->length = IB_MGMT_MAD_HDR;
+               packet->mad.hdr.status = ETIMEDOUT;
+               if (!queue_packet(file, agent, packet))
+                       return;
        }
-out:
        kfree(packet);
 }
 
@@ -209,22 +211,20 @@ static void recv_handler(struct ib_mad_agent *agent,
 {
        struct ib_umad_file *file = agent->context;
        struct ib_umad_packet *packet;
-       int length;
 
        if (mad_recv_wc->wc->status != IB_WC_SUCCESS)
-               goto out;
+               goto err1;
 
-       length = mad_recv_wc->mad_len;
-       packet = kzalloc(sizeof *packet + length, GFP_KERNEL);
+       packet = kzalloc(sizeof *packet, GFP_KERNEL);
        if (!packet)
-               goto out;
+               goto err1;
 
-       packet->length = length;
-
-       ib_coalesce_recv_mad(mad_recv_wc, packet->mad.data);
+       packet->length = mad_recv_wc->mad_len;
+       packet->recv_wc = mad_recv_wc;
 
        packet->mad.hdr.status    = 0;
-       packet->mad.hdr.length    = length + sizeof (struct ib_user_mad);
+       packet->mad.hdr.length    = sizeof (struct ib_user_mad) +
+                                   mad_recv_wc->mad_len;
        packet->mad.hdr.qpn       = cpu_to_be32(mad_recv_wc->wc->src_qp);
        packet->mad.hdr.lid       = cpu_to_be16(mad_recv_wc->wc->slid);
        packet->mad.hdr.sl        = mad_recv_wc->wc->sl;
@@ -240,12 +240,79 @@ static void recv_handler(struct ib_mad_agent *agent,
        }
 
        if (queue_packet(file, agent, packet))
-               kfree(packet);
+               goto err2;
+       return;
 
-out:
+err2:
+       kfree(packet);
+err1:
        ib_free_recv_mad(mad_recv_wc);
 }
 
+static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
+                            size_t count)
+{
+       struct ib_mad_recv_buf *recv_buf;
+       int left, seg_payload, offset, max_seg_payload;
+
+       /* We need enough room to copy the first (or only) MAD segment. */
+       recv_buf = &packet->recv_wc->recv_buf;
+       if ((packet->length <= sizeof (*recv_buf->mad) &&
+            count < sizeof (packet->mad) + packet->length) ||
+           (packet->length > sizeof (*recv_buf->mad) &&
+            count < sizeof (packet->mad) + sizeof (*recv_buf->mad)))
+               return -EINVAL;
+
+       if (copy_to_user(buf, &packet->mad, sizeof (packet->mad)))
+               return -EFAULT;
+
+       buf += sizeof (packet->mad);
+       seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad));
+       if (copy_to_user(buf, recv_buf->mad, seg_payload))
+               return -EFAULT;
+
+       if (seg_payload < packet->length) {
+               /*
+                * Multipacket RMPP MAD message. Copy remainder of message.
+                * Note that last segment may have a shorter payload.
+                */
+               if (count < sizeof (packet->mad) + packet->length) {
+                       /*
+                        * The buffer is too small, return the first RMPP segment,
+                        * which includes the RMPP message length.
+                        */
+                       return -ENOSPC;
+               }
+               offset = data_offset(recv_buf->mad->mad_hdr.mgmt_class);
+               max_seg_payload = sizeof (struct ib_mad) - offset;
+
+               for (left = packet->length - seg_payload, buf += seg_payload;
+                    left; left -= seg_payload, buf += seg_payload) {
+                       recv_buf = container_of(recv_buf->list.next,
+                                               struct ib_mad_recv_buf, list);
+                       seg_payload = min(left, max_seg_payload);
+                       if (copy_to_user(buf, ((void *) recv_buf->mad) + offset,
+                                        seg_payload))
+                               return -EFAULT;
+               }
+       }
+       return sizeof (packet->mad) + packet->length;
+}
+
+static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet,
+                            size_t count)
+{
+       ssize_t size = sizeof (packet->mad) + packet->length;
+
+       if (count < size)
+               return -EINVAL;
+
+       if (copy_to_user(buf, &packet->mad, size))
+               return -EFAULT;
+
+       return size;
+}
+
 static ssize_t ib_umad_read(struct file *filp, char __user *buf,
                            size_t count, loff_t *pos)
 {
@@ -253,7 +320,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
        struct ib_umad_packet *packet;
        ssize_t ret;
 
-       if (count < sizeof (struct ib_user_mad) + sizeof (struct ib_mad))
+       if (count < sizeof (struct ib_user_mad))
                return -EINVAL;
 
        spin_lock_irq(&file->recv_lock);
@@ -276,28 +343,44 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
 
        spin_unlock_irq(&file->recv_lock);
 
-       if (count < packet->length + sizeof (struct ib_user_mad)) {
-               /* Return length needed (and first RMPP segment) if too small */
-               if (copy_to_user(buf, &packet->mad,
-                                sizeof (struct ib_user_mad) + sizeof (struct ib_mad)))
-                       ret = -EFAULT;
-               else
-                       ret = -ENOSPC;
-       } else if (copy_to_user(buf, &packet->mad,
-                               packet->length + sizeof (struct ib_user_mad)))
-               ret = -EFAULT;
+       if (packet->recv_wc)
+               ret = copy_recv_mad(buf, packet, count);
        else
-               ret = packet->length + sizeof (struct ib_user_mad);
+               ret = copy_send_mad(buf, packet, count);
+
        if (ret < 0) {
                /* Requeue packet */
                spin_lock_irq(&file->recv_lock);
                list_add(&packet->list, &file->recv_list);
                spin_unlock_irq(&file->recv_lock);
-       } else
+       } else {
+               if (packet->recv_wc)
+                       ib_free_recv_mad(packet->recv_wc);
                kfree(packet);
+       }
        return ret;
 }
 
+static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf)
+{
+       int left, seg;
+
+       /* Copy class specific header */
+       if ((msg->hdr_len > IB_MGMT_RMPP_HDR) &&
+           copy_from_user(msg->mad + IB_MGMT_RMPP_HDR, buf + IB_MGMT_RMPP_HDR,
+                          msg->hdr_len - IB_MGMT_RMPP_HDR))
+               return -EFAULT;
+
+       /* All headers are in place.  Copy data segments. */
+       for (seg = 1, left = msg->data_len, buf += msg->hdr_len; left > 0;
+            seg++, left -= msg->seg_size, buf += msg->seg_size) {
+               if (copy_from_user(ib_get_rmpp_segment(msg, seg), buf,
+                                  min(left, msg->seg_size)))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
 static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
                             size_t count, loff_t *pos)
 {
@@ -309,14 +392,12 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
        struct ib_rmpp_mad *rmpp_mad;
        u8 method;
        __be64 *tid;
-       int ret, length, hdr_len, copy_offset;
-       int rmpp_active, has_rmpp_header;
+       int ret, data_len, hdr_len, copy_offset, rmpp_active;
 
        if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)
                return -EINVAL;
 
-       length = count - sizeof (struct ib_user_mad);
-       packet = kmalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
+       packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
        if (!packet)
                return -ENOMEM;
 
@@ -363,35 +444,25 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
        if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
                hdr_len = IB_MGMT_SA_HDR;
                copy_offset = IB_MGMT_RMPP_HDR;
-               has_rmpp_header = 1;
+               rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
+                             IB_MGMT_RMPP_FLAG_ACTIVE;
        } else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START &&
                   rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) {
-                       hdr_len = IB_MGMT_VENDOR_HDR;
-                       copy_offset = IB_MGMT_RMPP_HDR;
-                       has_rmpp_header = 1;
+               hdr_len = IB_MGMT_VENDOR_HDR;
+               copy_offset = IB_MGMT_RMPP_HDR;
+               rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
+                             IB_MGMT_RMPP_FLAG_ACTIVE;
        } else {
                hdr_len = IB_MGMT_MAD_HDR;
                copy_offset = IB_MGMT_MAD_HDR;
-               has_rmpp_header = 0;
-       }
-
-       if (has_rmpp_header)
-               rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
-                             IB_MGMT_RMPP_FLAG_ACTIVE;
-       else
                rmpp_active = 0;
-
-       /* Validate that the management class can support RMPP */
-       if (rmpp_active && !agent->rmpp_version) {
-               ret = -EINVAL;
-               goto err_ah;
        }
 
+       data_len = count - sizeof (struct ib_user_mad) - hdr_len;
        packet->msg = ib_create_send_mad(agent,
                                         be32_to_cpu(packet->mad.hdr.qpn),
-                                        0, rmpp_active,
-                                        hdr_len, length - hdr_len,
-                                        GFP_KERNEL);
+                                        0, rmpp_active, hdr_len,
+                                        data_len, GFP_KERNEL);
        if (IS_ERR(packet->msg)) {
                ret = PTR_ERR(packet->msg);
                goto err_ah;
@@ -402,14 +473,21 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
        packet->msg->retries    = packet->mad.hdr.retries;
        packet->msg->context[0] = packet;
 
-       /* Copy MAD headers (RMPP header in place) */
+       /* Copy MAD header.  Any RMPP header is already in place. */
        memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
-       /* Now, copy rest of message from user into send buffer */
-       if (copy_from_user(packet->msg->mad + copy_offset,
-                          buf + sizeof (struct ib_user_mad) + copy_offset,
-                          length - copy_offset)) {
-               ret = -EFAULT;
-               goto err_msg;
+       buf += sizeof (struct ib_user_mad);
+
+       if (!rmpp_active) {
+               if (copy_from_user(packet->msg->mad + copy_offset,
+                                  buf + copy_offset,
+                                  hdr_len + data_len - copy_offset)) {
+                       ret = -EFAULT;
+                       goto err_msg;
+               }
+       } else {
+               ret = copy_rmpp_mad(packet->msg, buf);
+               if (ret)
+                       goto err_msg;
        }
 
        /*
@@ -433,18 +511,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
                goto err_msg;
 
        up_read(&file->port->mutex);
-
        return count;
 
 err_msg:
        ib_free_send_mad(packet->msg);
-
 err_ah:
        ib_destroy_ah(ah);
-
 err_up:
        up_read(&file->port->mutex);
-
 err:
        kfree(packet);
        return ret;
@@ -627,8 +701,11 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
        already_dead = file->agents_dead;
        file->agents_dead = 1;
 
-       list_for_each_entry_safe(packet, tmp, &file->recv_list, list)
+       list_for_each_entry_safe(packet, tmp, &file->recv_list, list) {
+               if (packet->recv_wc)
+                       ib_free_recv_mad(packet->recv_wc);
                kfree(packet);
+       }
 
        list_del(&file->port_list);
 
index f7eecbc..3372d67 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 PathScale, Inc. All rights reserved.
@@ -178,10 +178,12 @@ IB_UVERBS_DECLARE_CMD(reg_mr);
 IB_UVERBS_DECLARE_CMD(dereg_mr);
 IB_UVERBS_DECLARE_CMD(create_comp_channel);
 IB_UVERBS_DECLARE_CMD(create_cq);
+IB_UVERBS_DECLARE_CMD(resize_cq);
 IB_UVERBS_DECLARE_CMD(poll_cq);
 IB_UVERBS_DECLARE_CMD(req_notify_cq);
 IB_UVERBS_DECLARE_CMD(destroy_cq);
 IB_UVERBS_DECLARE_CMD(create_qp);
+IB_UVERBS_DECLARE_CMD(query_qp);
 IB_UVERBS_DECLARE_CMD(modify_qp);
 IB_UVERBS_DECLARE_CMD(destroy_qp);
 IB_UVERBS_DECLARE_CMD(post_send);
@@ -193,6 +195,7 @@ IB_UVERBS_DECLARE_CMD(attach_mcast);
 IB_UVERBS_DECLARE_CMD(detach_mcast);
 IB_UVERBS_DECLARE_CMD(create_srq);
 IB_UVERBS_DECLARE_CMD(modify_srq);
+IB_UVERBS_DECLARE_CMD(query_srq);
 IB_UVERBS_DECLARE_CMD(destroy_srq);
 
 #endif /* UVERBS_H */
index 407b628..9f69bd4 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
+ * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -675,6 +676,46 @@ err:
        return ret;
 }
 
+ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
+                           const char __user *buf, int in_len,
+                           int out_len)
+{
+       struct ib_uverbs_resize_cq      cmd;
+       struct ib_uverbs_resize_cq_resp resp;
+       struct ib_udata                 udata;
+       struct ib_cq                    *cq;
+       int                             ret = -EINVAL;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       INIT_UDATA(&udata, buf + sizeof cmd,
+                  (unsigned long) cmd.response + sizeof resp,
+                  in_len - sizeof cmd, out_len - sizeof resp);
+
+       mutex_lock(&ib_uverbs_idr_mutex);
+
+       cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
+       if (!cq || cq->uobject->context != file->ucontext || !cq->device->resize_cq)
+               goto out;
+
+       ret = cq->device->resize_cq(cq, cmd.cqe, &udata);
+       if (ret)
+               goto out;
+
+       memset(&resp, 0, sizeof resp);
+       resp.cqe = cq->cqe;
+
+       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+                        &resp, sizeof resp))
+               ret = -EFAULT;
+
+out:
+       mutex_unlock(&ib_uverbs_idr_mutex);
+
+       return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
                          const char __user *buf, int in_len,
                          int out_len)
@@ -956,6 +997,106 @@ err_up:
        return ret;
 }
 
+ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
+                          const char __user *buf, int in_len,
+                          int out_len)
+{
+       struct ib_uverbs_query_qp      cmd;
+       struct ib_uverbs_query_qp_resp resp;
+       struct ib_qp                   *qp;
+       struct ib_qp_attr              *attr;
+       struct ib_qp_init_attr         *init_attr;
+       int                            ret;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       attr      = kmalloc(sizeof *attr, GFP_KERNEL);
+       init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
+       if (!attr || !init_attr) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mutex_lock(&ib_uverbs_idr_mutex);
+
+       qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+       if (qp && qp->uobject->context == file->ucontext)
+               ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
+       else
+               ret = -EINVAL;
+
+       mutex_unlock(&ib_uverbs_idr_mutex);
+
+       if (ret)
+               goto out;
+
+       memset(&resp, 0, sizeof resp);
+
+       resp.qp_state               = attr->qp_state;
+       resp.cur_qp_state           = attr->cur_qp_state;
+       resp.path_mtu               = attr->path_mtu;
+       resp.path_mig_state         = attr->path_mig_state;
+       resp.qkey                   = attr->qkey;
+       resp.rq_psn                 = attr->rq_psn;
+       resp.sq_psn                 = attr->sq_psn;
+       resp.dest_qp_num            = attr->dest_qp_num;
+       resp.qp_access_flags        = attr->qp_access_flags;
+       resp.pkey_index             = attr->pkey_index;
+       resp.alt_pkey_index         = attr->alt_pkey_index;
+       resp.en_sqd_async_notify    = attr->en_sqd_async_notify;
+       resp.max_rd_atomic          = attr->max_rd_atomic;
+       resp.max_dest_rd_atomic     = attr->max_dest_rd_atomic;
+       resp.min_rnr_timer          = attr->min_rnr_timer;
+       resp.port_num               = attr->port_num;
+       resp.timeout                = attr->timeout;
+       resp.retry_cnt              = attr->retry_cnt;
+       resp.rnr_retry              = attr->rnr_retry;
+       resp.alt_port_num           = attr->alt_port_num;
+       resp.alt_timeout            = attr->alt_timeout;
+
+       memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16);
+       resp.dest.flow_label        = attr->ah_attr.grh.flow_label;
+       resp.dest.sgid_index        = attr->ah_attr.grh.sgid_index;
+       resp.dest.hop_limit         = attr->ah_attr.grh.hop_limit;
+       resp.dest.traffic_class     = attr->ah_attr.grh.traffic_class;
+       resp.dest.dlid              = attr->ah_attr.dlid;
+       resp.dest.sl                = attr->ah_attr.sl;
+       resp.dest.src_path_bits     = attr->ah_attr.src_path_bits;
+       resp.dest.static_rate       = attr->ah_attr.static_rate;
+       resp.dest.is_global         = !!(attr->ah_attr.ah_flags & IB_AH_GRH);
+       resp.dest.port_num          = attr->ah_attr.port_num;
+
+       memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16);
+       resp.alt_dest.flow_label    = attr->alt_ah_attr.grh.flow_label;
+       resp.alt_dest.sgid_index    = attr->alt_ah_attr.grh.sgid_index;
+       resp.alt_dest.hop_limit     = attr->alt_ah_attr.grh.hop_limit;
+       resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class;
+       resp.alt_dest.dlid          = attr->alt_ah_attr.dlid;
+       resp.alt_dest.sl            = attr->alt_ah_attr.sl;
+       resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits;
+       resp.alt_dest.static_rate   = attr->alt_ah_attr.static_rate;
+       resp.alt_dest.is_global     = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH);
+       resp.alt_dest.port_num      = attr->alt_ah_attr.port_num;
+
+       resp.max_send_wr            = init_attr->cap.max_send_wr;
+       resp.max_recv_wr            = init_attr->cap.max_recv_wr;
+       resp.max_send_sge           = init_attr->cap.max_send_sge;
+       resp.max_recv_sge           = init_attr->cap.max_recv_sge;
+       resp.max_inline_data        = init_attr->cap.max_inline_data;
+       resp.sq_sig_all             = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
+
+       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+                        &resp, sizeof resp))
+               ret = -EFAULT;
+
+out:
+       kfree(attr);
+       kfree(init_attr);
+
+       return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
                            const char __user *buf, int in_len,
                            int out_len)
@@ -990,7 +1131,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
        attr->dest_qp_num         = cmd.dest_qp_num;
        attr->qp_access_flags     = cmd.qp_access_flags;
        attr->pkey_index          = cmd.pkey_index;
-       attr->alt_pkey_index      = cmd.pkey_index;
+       attr->alt_pkey_index      = cmd.alt_pkey_index;
        attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
        attr->max_rd_atomic       = cmd.max_rd_atomic;
        attr->max_dest_rd_atomic  = cmd.max_dest_rd_atomic;
@@ -1094,8 +1235,8 @@ out:
 }
 
 ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+                           const char __user *buf, int in_len,
+                           int out_len)
 {
        struct ib_uverbs_post_send      cmd;
        struct ib_uverbs_post_send_resp resp;
@@ -1323,8 +1464,8 @@ err:
 }
 
 ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+                           const char __user *buf, int in_len,
+                           int out_len)
 {
        struct ib_uverbs_post_recv      cmd;
        struct ib_uverbs_post_recv_resp resp;
@@ -1374,8 +1515,8 @@ out:
 }
 
 ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+                               const char __user *buf, int in_len,
+                               int out_len)
 {
        struct ib_uverbs_post_srq_recv      cmd;
        struct ib_uverbs_post_srq_recv_resp resp;
@@ -1723,6 +1864,8 @@ retry:
                goto err_destroy;
 
        resp.srq_handle = uobj->uobject.id;
+       resp.max_wr     = attr.attr.max_wr;
+       resp.max_sge    = attr.attr.max_sge;
 
        if (copy_to_user((void __user *) (unsigned long) cmd.response,
                         &resp, sizeof resp)) {
@@ -1783,6 +1926,49 @@ out:
        return ret ? ret : in_len;
 }
 
+ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
+                           const char __user *buf,
+                           int in_len, int out_len)
+{
+       struct ib_uverbs_query_srq      cmd;
+       struct ib_uverbs_query_srq_resp resp;
+       struct ib_srq_attr              attr;
+       struct ib_srq                   *srq;
+       int                             ret;
+
+       if (out_len < sizeof resp)
+               return -ENOSPC;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       mutex_lock(&ib_uverbs_idr_mutex);
+
+       srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+       if (srq && srq->uobject->context == file->ucontext)
+               ret = ib_query_srq(srq, &attr);
+       else
+               ret = -EINVAL;
+
+       mutex_unlock(&ib_uverbs_idr_mutex);
+
+       if (ret)
+               goto out;
+
+       memset(&resp, 0, sizeof resp);
+
+       resp.max_wr    = attr.max_wr;
+       resp.max_sge   = attr.max_sge;
+       resp.srq_limit = attr.srq_limit;
+
+       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+                        &resp, sizeof resp))
+               ret = -EFAULT;
+
+out:
+       return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
                              const char __user *buf, int in_len,
                              int out_len)
index 903f85a..ff092a0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 PathScale, Inc. All rights reserved.
@@ -91,10 +91,12 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
        [IB_USER_VERBS_CMD_DEREG_MR]            = ib_uverbs_dereg_mr,
        [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel,
        [IB_USER_VERBS_CMD_CREATE_CQ]           = ib_uverbs_create_cq,
+       [IB_USER_VERBS_CMD_RESIZE_CQ]           = ib_uverbs_resize_cq,
        [IB_USER_VERBS_CMD_POLL_CQ]             = ib_uverbs_poll_cq,
        [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ]       = ib_uverbs_req_notify_cq,
        [IB_USER_VERBS_CMD_DESTROY_CQ]          = ib_uverbs_destroy_cq,
        [IB_USER_VERBS_CMD_CREATE_QP]           = ib_uverbs_create_qp,
+       [IB_USER_VERBS_CMD_QUERY_QP]            = ib_uverbs_query_qp,
        [IB_USER_VERBS_CMD_MODIFY_QP]           = ib_uverbs_modify_qp,
        [IB_USER_VERBS_CMD_DESTROY_QP]          = ib_uverbs_destroy_qp,
        [IB_USER_VERBS_CMD_POST_SEND]           = ib_uverbs_post_send,
@@ -106,6 +108,7 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
        [IB_USER_VERBS_CMD_DETACH_MCAST]        = ib_uverbs_detach_mcast,
        [IB_USER_VERBS_CMD_CREATE_SRQ]          = ib_uverbs_create_srq,
        [IB_USER_VERBS_CMD_MODIFY_SRQ]          = ib_uverbs_modify_srq,
+       [IB_USER_VERBS_CMD_QUERY_SRQ]           = ib_uverbs_query_srq,
        [IB_USER_VERBS_CMD_DESTROY_SRQ]         = ib_uverbs_destroy_srq,
 };
 
@@ -461,7 +464,6 @@ void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr)
        ib_uverbs_async_handler(uobj->uverbs_file, uobj->uobject.user_handle,
                                event->event, &uobj->async_list,
                                &uobj->async_events_reported);
-                               
 }
 
 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
index c857361..cae0845 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -245,6 +245,258 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
 }
 EXPORT_SYMBOL(ib_create_qp);
 
+static const struct {
+       int                     valid;
+       enum ib_qp_attr_mask    req_param[IB_QPT_RAW_ETY + 1];
+       enum ib_qp_attr_mask    opt_param[IB_QPT_RAW_ETY + 1];
+} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+       [IB_QPS_RESET] = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR]   = { .valid = 1 },
+               [IB_QPS_INIT]  = {
+                       .valid = 1,
+                       .req_param = {
+                               [IB_QPT_UD]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_RC]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_SMI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                       }
+               },
+       },
+       [IB_QPS_INIT]  = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_INIT]  = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_RC]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_PORT                      |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_SMI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                       }
+               },
+               [IB_QPS_RTR]   = {
+                       .valid = 1,
+                       .req_param = {
+                               [IB_QPT_UC]  = (IB_QP_AV                        |
+                                               IB_QP_PATH_MTU                  |
+                                               IB_QP_DEST_QPN                  |
+                                               IB_QP_RQ_PSN),
+                               [IB_QPT_RC]  = (IB_QP_AV                        |
+                                               IB_QP_PATH_MTU                  |
+                                               IB_QP_DEST_QPN                  |
+                                               IB_QP_RQ_PSN                    |
+                                               IB_QP_MAX_DEST_RD_ATOMIC        |
+                                               IB_QP_MIN_RNR_TIMER),
+                       },
+                       .opt_param = {
+                                [IB_QPT_UD]  = (IB_QP_PKEY_INDEX               |
+                                                IB_QP_QKEY),
+                                [IB_QPT_UC]  = (IB_QP_ALT_PATH                 |
+                                                IB_QP_ACCESS_FLAGS             |
+                                                IB_QP_PKEY_INDEX),
+                                [IB_QPT_RC]  = (IB_QP_ALT_PATH                 |
+                                                IB_QP_ACCESS_FLAGS             |
+                                                IB_QP_PKEY_INDEX),
+                                [IB_QPT_SMI] = (IB_QP_PKEY_INDEX               |
+                                                IB_QP_QKEY),
+                                [IB_QPT_GSI] = (IB_QP_PKEY_INDEX               |
+                                                IB_QP_QKEY),
+                        }
+               }
+       },
+       [IB_QPS_RTR]   = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_RTS]   = {
+                       .valid = 1,
+                       .req_param = {
+                               [IB_QPT_UD]  = IB_QP_SQ_PSN,
+                               [IB_QPT_UC]  = IB_QP_SQ_PSN,
+                               [IB_QPT_RC]  = (IB_QP_TIMEOUT                   |
+                                               IB_QP_RETRY_CNT                 |
+                                               IB_QP_RNR_RETRY                 |
+                                               IB_QP_SQ_PSN                    |
+                                               IB_QP_MAX_QP_RD_ATOMIC),
+                               [IB_QPT_SMI] = IB_QP_SQ_PSN,
+                               [IB_QPT_GSI] = IB_QP_SQ_PSN,
+                       },
+                       .opt_param = {
+                                [IB_QPT_UD]  = (IB_QP_CUR_STATE                |
+                                                IB_QP_QKEY),
+                                [IB_QPT_UC]  = (IB_QP_CUR_STATE                |
+                                                IB_QP_ALT_PATH                 |
+                                                IB_QP_ACCESS_FLAGS             |
+                                                IB_QP_PATH_MIG_STATE),
+                                [IB_QPT_RC]  = (IB_QP_CUR_STATE                |
+                                                IB_QP_ALT_PATH                 |
+                                                IB_QP_ACCESS_FLAGS             |
+                                                IB_QP_MIN_RNR_TIMER            |
+                                                IB_QP_PATH_MIG_STATE),
+                                [IB_QPT_SMI] = (IB_QP_CUR_STATE                |
+                                                IB_QP_QKEY),
+                                [IB_QPT_GSI] = (IB_QP_CUR_STATE                |
+                                                IB_QP_QKEY),
+                        }
+               }
+       },
+       [IB_QPS_RTS]   = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_RTS]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_RC]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_PATH_MIG_STATE            |
+                                               IB_QP_MIN_RNR_TIMER),
+                               [IB_QPT_SMI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                       }
+               },
+               [IB_QPS_SQD]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+                               [IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+                               [IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
+                               [IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
+                               [IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
+                       }
+               },
+       },
+       [IB_QPS_SQD]   = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_RTS]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_RC]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_MIN_RNR_TIMER             |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_SMI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                       }
+               },
+               [IB_QPS_SQD]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_AV                        |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_PKEY_INDEX                |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_RC]  = (IB_QP_PORT                      |
+                                               IB_QP_AV                        |
+                                               IB_QP_TIMEOUT                   |
+                                               IB_QP_RETRY_CNT                 |
+                                               IB_QP_RNR_RETRY                 |
+                                               IB_QP_MAX_QP_RD_ATOMIC          |
+                                               IB_QP_MAX_DEST_RD_ATOMIC        |
+                                               IB_QP_ALT_PATH                  |
+                                               IB_QP_ACCESS_FLAGS              |
+                                               IB_QP_PKEY_INDEX                |
+                                               IB_QP_MIN_RNR_TIMER             |
+                                               IB_QP_PATH_MIG_STATE),
+                               [IB_QPT_SMI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_PKEY_INDEX                |
+                                               IB_QP_QKEY),
+                       }
+               }
+       },
+       [IB_QPS_SQE]   = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 },
+               [IB_QPS_RTS]   = {
+                       .valid = 1,
+                       .opt_param = {
+                               [IB_QPT_UD]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_UC]  = (IB_QP_CUR_STATE                 |
+                                               IB_QP_ACCESS_FLAGS),
+                               [IB_QPT_SMI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                               [IB_QPT_GSI] = (IB_QP_CUR_STATE                 |
+                                               IB_QP_QKEY),
+                       }
+               }
+       },
+       [IB_QPS_ERR] = {
+               [IB_QPS_RESET] = { .valid = 1 },
+               [IB_QPS_ERR] =   { .valid = 1 }
+       }
+};
+
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+                      enum ib_qp_type type, enum ib_qp_attr_mask mask)
+{
+       enum ib_qp_attr_mask req_param, opt_param;
+
+       if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
+           next_state < 0 || next_state > IB_QPS_ERR)
+               return 0;
+
+       if (mask & IB_QP_CUR_STATE  &&
+           cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
+           cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
+               return 0;
+
+       if (!qp_state_table[cur_state][next_state].valid)
+               return 0;
+
+       req_param = qp_state_table[cur_state][next_state].req_param[type];
+       opt_param = qp_state_table[cur_state][next_state].opt_param[type];
+
+       if ((mask & req_param) != req_param)
+               return 0;
+
+       if (mask & ~(req_param | opt_param | IB_QP_STATE))
+               return 0;
+
+       return 1;
+}
+EXPORT_SYMBOL(ib_modify_qp_is_ok);
+
 int ib_modify_qp(struct ib_qp *qp,
                 struct ib_qp_attr *qp_attr,
                 int qp_attr_mask)
@@ -322,11 +574,10 @@ int ib_destroy_cq(struct ib_cq *cq)
 }
 EXPORT_SYMBOL(ib_destroy_cq);
 
-int ib_resize_cq(struct ib_cq *cq,
-                 int           cqe)
+int ib_resize_cq(struct ib_cq *cq, int cqe)
 {
        return cq->device->resize_cq ?
-               cq->device->resize_cq(cq, cqe) : -ENOSYS;
+               cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
 }
 EXPORT_SYMBOL(ib_resize_cq);
 
index a19e0ed..f023d39 100644 (file)
@@ -147,7 +147,7 @@ int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah)
        switch (ah->type) {
        case MTHCA_AH_ON_HCA:
                mthca_free(&dev->av_table.alloc,
-                          (ah->avdma - dev->av_table.ddr_av_base) /
+                          (ah->avdma - dev->av_table.ddr_av_base) /
                           MTHCA_AV_SIZE);
                break;
 
@@ -193,6 +193,37 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
        return 0;
 }
 
+int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr)
+{
+       struct mthca_ah *ah   = to_mah(ibah);
+       struct mthca_dev *dev = to_mdev(ibah->device);
+
+       /* Only implement for MAD and memfree ah for now. */
+       if (ah->type == MTHCA_AH_ON_HCA)
+               return -ENOSYS;
+
+       memset(attr, 0, sizeof *attr);
+       attr->dlid          = be16_to_cpu(ah->av->dlid);
+       attr->sl            = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
+       attr->static_rate   = ah->av->msg_sr & 0x7;
+       attr->src_path_bits = ah->av->g_slid & 0x7F;
+       attr->port_num      = be32_to_cpu(ah->av->port_pd) >> 24;
+       attr->ah_flags      = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0;
+
+       if (attr->ah_flags) {
+               attr->grh.traffic_class =
+                       be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20;
+               attr->grh.flow_label =
+                       be32_to_cpu(ah->av->sl_tclass_flowlabel) & 0xfffff;
+               attr->grh.hop_limit  = ah->av->hop_limit;
+               attr->grh.sgid_index = ah->av->gid_index &
+                                      (dev->limits.gid_table_len - 1);
+               memcpy(attr->grh.dgid.raw, ah->av->dgid, 16);
+       }
+
+       return 0;
+}
+
 int __devinit mthca_init_av_table(struct mthca_dev *dev)
 {
        int err;
index 2825615..343eca5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -182,25 +182,58 @@ struct mthca_cmd_context {
        u8                status;
 };
 
+static int fw_cmd_doorbell = 1;
+module_param(fw_cmd_doorbell, int, 0644);
+MODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero "
+                "(and supported by FW)");
+
 static inline int go_bit(struct mthca_dev *dev)
 {
        return readl(dev->hcr + HCR_STATUS_OFFSET) &
                swab32(1 << HCR_GO_BIT);
 }
 
-static int mthca_cmd_post(struct mthca_dev *dev,
-                         u64 in_param,
-                         u64 out_param,
-                         u32 in_modifier,
-                         u8 op_modifier,
-                         u16 op,
-                         u16 token,
-                         int event)
+static void mthca_cmd_post_dbell(struct mthca_dev *dev,
+                                u64 in_param,
+                                u64 out_param,
+                                u32 in_modifier,
+                                u8 op_modifier,
+                                u16 op,
+                                u16 token)
 {
-       int err = 0;
+       void __iomem *ptr = dev->cmd.dbell_map;
+       u16 *offs = dev->cmd.dbell_offsets;
 
-       mutex_lock(&dev->cmd.hcr_mutex);
+       __raw_writel((__force u32) cpu_to_be32(in_param >> 32),           ptr + offs[0]);
+       wmb();
+       __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  ptr + offs[1]);
+       wmb();
+       __raw_writel((__force u32) cpu_to_be32(in_modifier),              ptr + offs[2]);
+       wmb();
+       __raw_writel((__force u32) cpu_to_be32(out_param >> 32),          ptr + offs[3]);
+       wmb();
+       __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), ptr + offs[4]);
+       wmb();
+       __raw_writel((__force u32) cpu_to_be32(token << 16),              ptr + offs[5]);
+       wmb();
+       __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)                |
+                                              (1 << HCA_E_BIT)                 |
+                                              (op_modifier << HCR_OPMOD_SHIFT) |
+                                               op),                      ptr + offs[6]);
+       wmb();
+       __raw_writel((__force u32) 0,                                     ptr + offs[7]);
+       wmb();
+}
 
+static int mthca_cmd_post_hcr(struct mthca_dev *dev,
+                             u64 in_param,
+                             u64 out_param,
+                             u32 in_modifier,
+                             u8 op_modifier,
+                             u16 op,
+                             u16 token,
+                             int event)
+{
        if (event) {
                unsigned long end = jiffies + GO_BIT_TIMEOUT;
 
@@ -210,10 +243,8 @@ static int mthca_cmd_post(struct mthca_dev *dev,
                }
        }
 
-       if (go_bit(dev)) {
-               err = -EAGAIN;
-               goto out;
-       }
+       if (go_bit(dev))
+               return -EAGAIN;
 
        /*
         * We use writel (instead of something like memcpy_toio)
@@ -236,7 +267,29 @@ static int mthca_cmd_post(struct mthca_dev *dev,
                                               (op_modifier << HCR_OPMOD_SHIFT) |
                                               op),                       dev->hcr + 6 * 4);
 
-out:
+       return 0;
+}
+
+static int mthca_cmd_post(struct mthca_dev *dev,
+                         u64 in_param,
+                         u64 out_param,
+                         u32 in_modifier,
+                         u8 op_modifier,
+                         u16 op,
+                         u16 token,
+                         int event)
+{
+       int err = 0;
+
+       mutex_lock(&dev->cmd.hcr_mutex);
+
+       if (event && dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && fw_cmd_doorbell)
+               mthca_cmd_post_dbell(dev, in_param, out_param, in_modifier,
+                                          op_modifier, op, token);
+       else
+               err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
+                                        op_modifier, op, token, event);
+
        mutex_unlock(&dev->cmd.hcr_mutex);
        return err;
 }
@@ -275,7 +328,7 @@ static int mthca_cmd_poll(struct mthca_dev *dev,
        }
 
        if (out_is_imm)
-               *out_param = 
+               *out_param =
                        (u64) be32_to_cpu((__force __be32)
                                          __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
                        (u64) be32_to_cpu((__force __be32)
@@ -386,7 +439,7 @@ static int mthca_cmd_box(struct mthca_dev *dev,
                         unsigned long timeout,
                         u8 *status)
 {
-       if (dev->cmd.use_events)
+       if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
                return mthca_cmd_wait(dev, in_param, &out_param, 0,
                                      in_modifier, op_modifier, op,
                                      timeout, status);
@@ -423,7 +476,7 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
                         unsigned long timeout,
                         u8 *status)
 {
-       if (dev->cmd.use_events)
+       if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
                return mthca_cmd_wait(dev, in_param, out_param, 1,
                                      in_modifier, op_modifier, op,
                                      timeout, status);
@@ -437,7 +490,7 @@ int mthca_cmd_init(struct mthca_dev *dev)
 {
        mutex_init(&dev->cmd.hcr_mutex);
        sema_init(&dev->cmd.poll_sem, 1);
-       dev->cmd.use_events = 0;
+       dev->cmd.flags = 0;
 
        dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
                           MTHCA_HCR_SIZE);
@@ -461,6 +514,8 @@ void mthca_cmd_cleanup(struct mthca_dev *dev)
 {
        pci_pool_destroy(dev->cmd.pool);
        iounmap(dev->hcr);
+       if (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS)
+               iounmap(dev->cmd.dbell_map);
 }
 
 /*
@@ -498,7 +553,8 @@ int mthca_cmd_use_events(struct mthca_dev *dev)
                ; /* nothing */
        --dev->cmd.token_mask;
 
-       dev->cmd.use_events = 1;
+       dev->cmd.flags |= MTHCA_CMD_USE_EVENTS;
+
        down(&dev->cmd.poll_sem);
 
        return 0;
@@ -511,7 +567,7 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
 {
        int i;
 
-       dev->cmd.use_events = 0;
+       dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS;
 
        for (i = 0; i < dev->cmd.max_cmds; ++i)
                down(&dev->cmd.event_sem);
@@ -596,8 +652,9 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
                 * address or size and use that as our log2 size.
                 */
                lg = ffs(mthca_icm_addr(&iter) | mthca_icm_size(&iter)) - 1;
-               if (lg < 12) {
-                       mthca_warn(dev, "Got FW area not aligned to 4K (%llx/%lx).\n",
+               if (lg < MTHCA_ICM_PAGE_SHIFT) {
+                       mthca_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n",
+                                  MTHCA_ICM_PAGE_SIZE,
                                   (unsigned long long) mthca_icm_addr(&iter),
                                   mthca_icm_size(&iter));
                        err = -EINVAL;
@@ -609,8 +666,9 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
                                virt += 1 << lg;
                        }
 
-                       pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
-                                                          (i << lg)) | (lg - 12));
+                       pages[nent * 2 + 1] =
+                               cpu_to_be64((mthca_icm_addr(&iter) + (i << lg)) |
+                                           (lg - MTHCA_ICM_PAGE_SHIFT));
                        ts += 1 << (lg - 10);
                        ++tc;
 
@@ -661,12 +719,41 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
        return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A, status);
 }
 
+static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base)
+{
+       unsigned long addr;
+       u16 max_off = 0;
+       int i;
+
+       for (i = 0; i < 8; ++i)
+               max_off = max(max_off, dev->cmd.dbell_offsets[i]);
+
+       if ((base & PAGE_MASK) != ((base + max_off) & PAGE_MASK)) {
+               mthca_warn(dev, "Firmware doorbell region at 0x%016llx, "
+                          "length 0x%x crosses a page boundary\n",
+                          (unsigned long long) base, max_off);
+               return;
+       }
+
+       addr = pci_resource_start(dev->pdev, 2) +
+               ((pci_resource_len(dev->pdev, 2) - 1) & base);
+       dev->cmd.dbell_map = ioremap(addr, max_off + sizeof(u32));
+       if (!dev->cmd.dbell_map)
+               return;
+
+       dev->cmd.flags |= MTHCA_CMD_POST_DOORBELLS;
+       mthca_dbg(dev, "Mapped doorbell page for posting FW commands\n");
+}
+
 int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 {
        struct mthca_mailbox *mailbox;
        u32 *outbox;
+       u64 base;
+       u32 tmp;
        int err = 0;
        u8 lg;
+       int i;
 
 #define QUERY_FW_OUT_SIZE             0x100
 #define QUERY_FW_VER_OFFSET            0x00
@@ -674,6 +761,10 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 #define QUERY_FW_ERR_START_OFFSET      0x30
 #define QUERY_FW_ERR_SIZE_OFFSET       0x38
 
+#define QUERY_FW_CMD_DB_EN_OFFSET      0x10
+#define QUERY_FW_CMD_DB_OFFSET         0x50
+#define QUERY_FW_CMD_DB_BASE           0x60
+
 #define QUERY_FW_START_OFFSET          0x20
 #define QUERY_FW_END_OFFSET            0x28
 
@@ -702,16 +793,29 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
                ((dev->fw_ver & 0xffff0000ull) >> 16) |
                ((dev->fw_ver & 0x0000ffffull) << 16);
 
+       mthca_dbg(dev, "FW version %012llx, max commands %d\n",
+                 (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
+
        MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
        dev->cmd.max_cmds = 1 << lg;
        MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
        MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
 
-       mthca_dbg(dev, "FW version %012llx, max commands %d\n",
-                 (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
        mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n",
                  (unsigned long long) dev->catas_err.addr, dev->catas_err.size);
 
+       MTHCA_GET(tmp, outbox, QUERY_FW_CMD_DB_EN_OFFSET);
+       if (tmp & 0x1) {
+               mthca_dbg(dev, "FW supports commands through doorbells\n");
+
+               MTHCA_GET(base, outbox, QUERY_FW_CMD_DB_BASE);
+               for (i = 0; i < MTHCA_CMD_NUM_DBELL_DWORDS; ++i)
+                       MTHCA_GET(dev->cmd.dbell_offsets[i], outbox,
+                                 QUERY_FW_CMD_DB_OFFSET + (i << 1));
+
+               mthca_setup_cmd_doorbells(dev, base);
+       }
+
        if (mthca_is_memfree(dev)) {
                MTHCA_GET(dev->fw.arbel.fw_pages,       outbox, QUERY_FW_SIZE_OFFSET);
                MTHCA_GET(dev->fw.arbel.clr_int_base,   outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
@@ -720,12 +824,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
                mthca_dbg(dev, "FW size %d KB\n", dev->fw.arbel.fw_pages << 2);
 
                /*
-                * Arbel page size is always 4 KB; round up number of
-                * system pages needed.
+                * Round up number of system pages needed in case
+                * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
                 */
                dev->fw.arbel.fw_pages =
-                       ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE >> 12) >>
-                               (PAGE_SHIFT - 12);
+                       ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
+                               (PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
 
                mthca_dbg(dev, "Clear int @ %llx, EQ arm @ %llx, EQ set CI @ %llx\n",
                          (unsigned long long) dev->fw.arbel.clr_int_base,
@@ -1173,7 +1277,8 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
        int err;
 
 #define INIT_HCA_IN_SIZE                0x200
-#define INIT_HCA_FLAGS_OFFSET           0x014
+#define INIT_HCA_FLAGS1_OFFSET           0x00c
+#define INIT_HCA_FLAGS2_OFFSET           0x014
 #define INIT_HCA_QPC_OFFSET             0x020
 #define  INIT_HCA_QPC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x10)
 #define  INIT_HCA_LOG_QP_OFFSET         (INIT_HCA_QPC_OFFSET + 0x17)
@@ -1216,15 +1321,18 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 
        memset(inbox, 0, INIT_HCA_IN_SIZE);
 
+       if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+               MTHCA_PUT(inbox, 0x1, INIT_HCA_FLAGS1_OFFSET);
+
 #if defined(__LITTLE_ENDIAN)
-       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
+       *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
 #elif defined(__BIG_ENDIAN)
-       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1);
+       *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1 << 1);
 #else
 #error Host endianness not defined
 #endif
        /* Check port for UD address vector: */
-       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1);
+       *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1);
 
        /* We leave wqe_quota, responder_exu, etc as 0 (default) */
 
@@ -1438,11 +1546,11 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
                return ret;
 
        /*
-        * Arbel page size is always 4 KB; round up number of system
-        * pages needed.
+        * Round up number of system pages needed in case
+        * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
         */
-       *aux_pages = (*aux_pages + (1 << (PAGE_SHIFT - 12)) - 1) >> (PAGE_SHIFT - 12);
-       *aux_pages = ALIGN(*aux_pages, PAGE_SIZE >> 12) >> (PAGE_SHIFT - 12);
+       *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
+               (PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
 
        return 0;
 }
@@ -1514,6 +1622,37 @@ int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                             CMD_TIME_CLASS_A, status);
 }
 
+int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
+                   u8 *status)
+{
+       struct mthca_mailbox *mailbox;
+       __be32 *inbox;
+       int err;
+
+#define RESIZE_CQ_IN_SIZE              0x40
+#define RESIZE_CQ_LOG_SIZE_OFFSET      0x0c
+#define RESIZE_CQ_LKEY_OFFSET          0x1c
+
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       inbox = mailbox->buf;
+
+       memset(inbox, 0, RESIZE_CQ_IN_SIZE);
+       /*
+        * Leave start address fields zeroed out -- mthca assumes that
+        * MRs for CQs always start at virtual address 0.
+        */
+       MTHCA_PUT(inbox, log_size, RESIZE_CQ_LOG_SIZE_OFFSET);
+       MTHCA_PUT(inbox, lkey,     RESIZE_CQ_LKEY_OFFSET);
+
+       err = mthca_cmd(dev, mailbox->dma, cq_num, 1, CMD_RESIZE_CQ,
+                       CMD_TIME_CLASS_B, status);
+
+       mthca_free_mailbox(dev, mailbox);
+       return err;
+}
+
 int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int srq_num, u8 *status)
 {
@@ -1529,37 +1668,69 @@ int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                             CMD_TIME_CLASS_A, status);
 }
 
+int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
+                   struct mthca_mailbox *mailbox, u8 *status)
+{
+       return mthca_cmd_box(dev, 0, mailbox->dma, num, 0,
+                            CMD_QUERY_SRQ, CMD_TIME_CLASS_A, status);
+}
+
 int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status)
 {
        return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ,
                         CMD_TIME_CLASS_B, status);
 }
 
-int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-                   int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
+                   enum ib_qp_state next, u32 num, int is_ee,
+                   struct mthca_mailbox *mailbox, u32 optmask,
                    u8 *status)
 {
-       static const u16 op[] = {
-               [MTHCA_TRANS_RST2INIT]  = CMD_RST2INIT_QPEE,
-               [MTHCA_TRANS_INIT2INIT] = CMD_INIT2INIT_QPEE,
-               [MTHCA_TRANS_INIT2RTR]  = CMD_INIT2RTR_QPEE,
-               [MTHCA_TRANS_RTR2RTS]   = CMD_RTR2RTS_QPEE,
-               [MTHCA_TRANS_RTS2RTS]   = CMD_RTS2RTS_QPEE,
-               [MTHCA_TRANS_SQERR2RTS] = CMD_SQERR2RTS_QPEE,
-               [MTHCA_TRANS_ANY2ERR]   = CMD_2ERR_QPEE,
-               [MTHCA_TRANS_RTS2SQD]   = CMD_RTS2SQD_QPEE,
-               [MTHCA_TRANS_SQD2SQD]   = CMD_SQD2SQD_QPEE,
-               [MTHCA_TRANS_SQD2RTS]   = CMD_SQD2RTS_QPEE,
-               [MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
+       static const u16 op[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
+               [IB_QPS_RESET] = {
+                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
+                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
+                       [IB_QPS_INIT]   = CMD_RST2INIT_QPEE,
+               },
+               [IB_QPS_INIT]  = {
+                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
+                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
+                       [IB_QPS_INIT]   = CMD_INIT2INIT_QPEE,
+                       [IB_QPS_RTR]    = CMD_INIT2RTR_QPEE,
+               },
+               [IB_QPS_RTR]   = {
+                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
+                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
+                       [IB_QPS_RTS]    = CMD_RTR2RTS_QPEE,
+               },
+               [IB_QPS_RTS]   = {
+                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
+                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
+                       [IB_QPS_RTS]    = CMD_RTS2RTS_QPEE,
+                       [IB_QPS_SQD]    = CMD_RTS2SQD_QPEE,
+               },
+               [IB_QPS_SQD] = {
+                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
+                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
+                       [IB_QPS_RTS]    = CMD_SQD2RTS_QPEE,
+                       [IB_QPS_SQD]    = CMD_SQD2SQD_QPEE,
+               },
+               [IB_QPS_SQE] = {
+                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
+                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
+                       [IB_QPS_RTS]    = CMD_SQERR2RTS_QPEE,
+               },
+               [IB_QPS_ERR] = {
+                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
+                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
+               }
        };
+
        u8 op_mod = 0;
        int my_mailbox = 0;
        int err;
 
-       if (trans < 0 || trans >= ARRAY_SIZE(op))
-               return -EINVAL;
-
-       if (trans == MTHCA_TRANS_ANY2RST) {
+       if (op[cur][next] == CMD_ERR2RST_QPEE) {
                op_mod = 3;     /* don't write outbox, any->reset */
 
                /* For debugging */
@@ -1571,34 +1742,35 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
                        } else
                                mailbox = NULL;
                }
-       } else {
-               if (0) {
+
+               err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
+                                   (!!is_ee << 24) | num, op_mod,
+                                   op[cur][next], CMD_TIME_CLASS_C, status);
+
+               if (0 && mailbox) {
                        int i;
                        mthca_dbg(dev, "Dumping QP context:\n");
-                       printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
+                       printk(" %08x\n", be32_to_cpup(mailbox->buf));
                        for (i = 0; i < 0x100 / 4; ++i) {
                                if (i % 8 == 0)
-                                       printk("  [%02x] ", i * 4);
+                                       printk("[%02x] ", i * 4);
                                printk(" %08x",
                                       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
                                if ((i + 1) % 8 == 0)
                                        printk("\n");
                        }
                }
-       }
-
-       if (trans == MTHCA_TRANS_ANY2RST) {
-               err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
-                                   (!!is_ee << 24) | num, op_mod,
-                                   op[trans], CMD_TIME_CLASS_C, status);
 
-               if (0 && mailbox) {
+               if (my_mailbox)
+                       mthca_free_mailbox(dev, mailbox);
+       } else {
+               if (0) {
                        int i;
                        mthca_dbg(dev, "Dumping QP context:\n");
-                       printk(" %08x\n", be32_to_cpup(mailbox->buf));
+                       printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
                        for (i = 0; i < 0x100 / 4; ++i) {
                                if (i % 8 == 0)
-                                       printk("[%02x] ", i * 4);
+                                       printk("  [%02x] ", i * 4);
                                printk(" %08x",
                                       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
                                if ((i + 1) % 8 == 0)
@@ -1606,12 +1778,9 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
                        }
                }
 
-       } else
-               err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
-                               op_mod, op[trans], CMD_TIME_CLASS_C, status);
-
-       if (my_mailbox)
-               mthca_free_mailbox(dev, mailbox);
+               err = mthca_cmd(dev, mailbox->dma, optmask | (!!is_ee << 24) | num,
+                               op_mod, op[cur][next], CMD_TIME_CLASS_C, status);
+       }
 
        return err;
 }
index 18175be..e4ec35c 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -73,9 +74,9 @@ enum {
        MTHCA_CMD_STAT_REG_BOUND      = 0x21,
        /* HCA local attached memory not present: */
        MTHCA_CMD_STAT_LAM_NOT_PRE    = 0x22,
-        /* Bad management packet (silently discarded): */
+       /* Bad management packet (silently discarded): */
        MTHCA_CMD_STAT_BAD_PKT        = 0x30,
-        /* More outstanding CQEs in CQ than new CQ size: */
+       /* More outstanding CQEs in CQ than new CQ size: */
        MTHCA_CMD_STAT_BAD_SIZE       = 0x40
 };
 
@@ -298,13 +299,18 @@ int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int cq_num, u8 *status);
 int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                   int cq_num, u8 *status);
+int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
+                   u8 *status);
 int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int srq_num, u8 *status);
 int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int srq_num, u8 *status);
+int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
+                   struct mthca_mailbox *mailbox, u8 *status);
 int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status);
-int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
-                   int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
+                   enum ib_qp_state next, u32 num, int is_ee,
+                   struct mthca_mailbox *mailbox, u32 optmask,
                    u8 *status);
 int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
                   struct mthca_mailbox *mailbox, u8 *status);
index 96f1a86..76aabc5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems, Inc. All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -150,24 +150,29 @@ struct mthca_err_cqe {
 #define MTHCA_ARBEL_CQ_DB_REQ_NOT      (2 << 24)
 #define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24)
 
-static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
+static inline struct mthca_cqe *get_cqe_from_buf(struct mthca_cq_buf *buf,
+                                                int entry)
 {
-       if (cq->is_direct)
-               return cq->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
+       if (buf->is_direct)
+               return buf->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
        else
-               return cq->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
+               return buf->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
                        + (entry * MTHCA_CQ_ENTRY_SIZE) % PAGE_SIZE;
 }
 
-static inline struct mthca_cqe *cqe_sw(struct mthca_cq *cq, int i)
+static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
+{
+       return get_cqe_from_buf(&cq->buf, entry);
+}
+
+static inline struct mthca_cqe *cqe_sw(struct mthca_cqe *cqe)
 {
-       struct mthca_cqe *cqe = get_cqe(cq, i);
        return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe;
 }
 
 static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq)
 {
-       return cqe_sw(cq, cq->cons_index & cq->ibcq.cqe);
+       return cqe_sw(get_cqe(cq, cq->cons_index & cq->ibcq.cqe));
 }
 
 static inline void set_cqe_hw(struct mthca_cqe *cqe)
@@ -289,7 +294,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
         * from our QP and therefore don't need to be checked.
         */
        for (prod_index = cq->cons_index;
-            cqe_sw(cq, prod_index & cq->ibcq.cqe);
+            cqe_sw(get_cqe(cq, prod_index & cq->ibcq.cqe));
             ++prod_index)
                if (prod_index == cq->cons_index + cq->ibcq.cqe)
                        break;
@@ -324,12 +329,58 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
                wake_up(&cq->wait);
 }
 
-static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
-                           struct mthca_qp *qp, int wqe_index, int is_send,
-                           struct mthca_err_cqe *cqe,
-                           struct ib_wc *entry, int *free_cqe)
+void mthca_cq_resize_copy_cqes(struct mthca_cq *cq)
+{
+       int i;
+
+       /*
+        * In Tavor mode, the hardware keeps the consumer and producer
+        * indices mod the CQ size.  Since we might be making the CQ
+        * bigger, we need to deal with the case where the producer
+        * index wrapped around before the CQ was resized.
+        */
+       if (!mthca_is_memfree(to_mdev(cq->ibcq.device)) &&
+           cq->ibcq.cqe < cq->resize_buf->cqe) {
+               cq->cons_index &= cq->ibcq.cqe;
+               if (cqe_sw(get_cqe(cq, cq->ibcq.cqe)))
+                       cq->cons_index -= cq->ibcq.cqe + 1;
+       }
+
+       for (i = cq->cons_index; cqe_sw(get_cqe(cq, i & cq->ibcq.cqe)); ++i)
+               memcpy(get_cqe_from_buf(&cq->resize_buf->buf,
+                                       i & cq->resize_buf->cqe),
+                      get_cqe(cq, i & cq->ibcq.cqe), MTHCA_CQ_ENTRY_SIZE);
+}
+
+int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent)
+{
+       int ret;
+       int i;
+
+       ret = mthca_buf_alloc(dev, nent * MTHCA_CQ_ENTRY_SIZE,
+                             MTHCA_MAX_DIRECT_CQ_SIZE,
+                             &buf->queue, &buf->is_direct,
+                             &dev->driver_pd, 1, &buf->mr);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < nent; ++i)
+               set_cqe_hw(get_cqe_from_buf(buf, i));
+
+       return 0;
+}
+
+void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe)
+{
+       mthca_buf_free(dev, (cqe + 1) * MTHCA_CQ_ENTRY_SIZE, &buf->queue,
+                      buf->is_direct, &buf->mr);
+}
+
+static void handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
+                            struct mthca_qp *qp, int wqe_index, int is_send,
+                            struct mthca_err_cqe *cqe,
+                            struct ib_wc *entry, int *free_cqe)
 {
-       int err;
        int dbd;
        __be32 new_wqe;
 
@@ -412,11 +463,9 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
         * error case, so we don't have to check the doorbell count, etc.
         */
        if (mthca_is_memfree(dev))
-               return 0;
+               return;
 
-       err = mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
-       if (err)
-               return err;
+       mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
 
        /*
         * If we're at the end of the WQE chain, or we've used up our
@@ -424,15 +473,13 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
         * the next poll operation.
         */
        if (!(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd))
-               return 0;
+               return;
 
        cqe->db_cnt   = cpu_to_be16(be16_to_cpu(cqe->db_cnt) - dbd);
        cqe->wqe      = new_wqe;
        cqe->syndrome = SYNDROME_WR_FLUSH_ERR;
 
        *free_cqe = 0;
-
-       return 0;
 }
 
 static inline int mthca_poll_one(struct mthca_dev *dev,
@@ -518,9 +565,9 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
        }
 
        if (is_error) {
-               err = handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
-                                      (struct mthca_err_cqe *) cqe,
-                                      entry, &free_cqe);
+               handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
+                                (struct mthca_err_cqe *) cqe,
+                                entry, &free_cqe);
                goto out;
        }
 
@@ -614,11 +661,14 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
 
        spin_lock_irqsave(&cq->lock, flags);
 
-       for (npolled = 0; npolled < num_entries; ++npolled) {
+       npolled = 0;
+repoll:
+       while (npolled < num_entries) {
                err = mthca_poll_one(dev, cq, &qp,
                                     &freed, entry + npolled);
                if (err)
                        break;
+               ++npolled;
        }
 
        if (freed) {
@@ -626,6 +676,42 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
                update_cons_index(dev, cq, freed);
        }
 
+       /*
+        * If a CQ resize is in progress and we discovered that the
+        * old buffer is empty, then peek in the new buffer, and if
+        * it's not empty, switch to the new buffer and continue
+        * polling there.
+        */
+       if (unlikely(err == -EAGAIN && cq->resize_buf &&
+                    cq->resize_buf->state == CQ_RESIZE_READY)) {
+               /*
+                * In Tavor mode, the hardware keeps the producer
+                * index modulo the CQ size.  Since we might be making
+                * the CQ bigger, we need to mask our consumer index
+                * using the size of the old CQ buffer before looking
+                * in the new CQ buffer.
+                */
+               if (!mthca_is_memfree(dev))
+                       cq->cons_index &= cq->ibcq.cqe;
+
+               if (cqe_sw(get_cqe_from_buf(&cq->resize_buf->buf,
+                                           cq->cons_index & cq->resize_buf->cqe))) {
+                       struct mthca_cq_buf tbuf;
+                       int tcqe;
+
+                       tbuf         = cq->buf;
+                       tcqe         = cq->ibcq.cqe;
+                       cq->buf      = cq->resize_buf->buf;
+                       cq->ibcq.cqe = cq->resize_buf->cqe;
+
+                       cq->resize_buf->buf   = tbuf;
+                       cq->resize_buf->cqe   = tcqe;
+                       cq->resize_buf->state = CQ_RESIZE_SWAPPED;
+
+                       goto repoll;
+               }
+       }
+
        spin_unlock_irqrestore(&cq->lock, flags);
 
        return err == 0 || err == -EAGAIN ? npolled : err;
@@ -684,24 +770,14 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
        return 0;
 }
 
-static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
-{
-       mthca_buf_free(dev, (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
-                      &cq->queue, cq->is_direct, &cq->mr);
-}
-
 int mthca_init_cq(struct mthca_dev *dev, int nent,
                  struct mthca_ucontext *ctx, u32 pdn,
                  struct mthca_cq *cq)
 {
-       int size = nent * MTHCA_CQ_ENTRY_SIZE;
        struct mthca_mailbox *mailbox;
        struct mthca_cq_context *cq_context;
        int err = -ENOMEM;
        u8 status;
-       int i;
-
-       might_sleep();
 
        cq->ibcq.cqe  = nent - 1;
        cq->is_kernel = !ctx;
@@ -739,14 +815,9 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
        cq_context = mailbox->buf;
 
        if (cq->is_kernel) {
-               err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_CQ_SIZE,
-                                     &cq->queue, &cq->is_direct,
-                                     &dev->driver_pd, 1, &cq->mr);
+               err = mthca_alloc_cq_buf(dev, &cq->buf, nent);
                if (err)
                        goto err_out_mailbox;
-
-               for (i = 0; i < nent; ++i)
-                       set_cqe_hw(get_cqe(cq, i));
        }
 
        spin_lock_init(&cq->lock);
@@ -765,7 +836,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
        cq_context->error_eqn       = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
        cq_context->comp_eqn        = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
        cq_context->pd              = cpu_to_be32(pdn);
-       cq_context->lkey            = cpu_to_be32(cq->mr.ibmr.lkey);
+       cq_context->lkey            = cpu_to_be32(cq->buf.mr.ibmr.lkey);
        cq_context->cqn             = cpu_to_be32(cq->cqn);
 
        if (mthca_is_memfree(dev)) {
@@ -803,7 +874,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 
 err_out_free_mr:
        if (cq->is_kernel)
-               mthca_free_cq_buf(dev, cq);
+               mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
 
 err_out_mailbox:
        mthca_free_mailbox(dev, mailbox);
@@ -832,8 +903,6 @@ void mthca_free_cq(struct mthca_dev *dev,
        int err;
        u8 status;
 
-       might_sleep();
-
        mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
        if (IS_ERR(mailbox)) {
                mthca_warn(dev, "No memory for mailbox to free CQ.\n");
@@ -871,7 +940,7 @@ void mthca_free_cq(struct mthca_dev *dev,
        wait_event(cq->wait, !atomic_read(&cq->refcount));
 
        if (cq->is_kernel) {
-               mthca_free_cq_buf(dev, cq);
+               mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
                if (mthca_is_memfree(dev)) {
                        mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
                        mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
index e481037..ad52edb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -53,8 +53,8 @@
 
 #define DRV_NAME       "ib_mthca"
 #define PFX            DRV_NAME ": "
-#define DRV_VERSION    "0.07"
-#define DRV_RELDATE    "February 13, 2006"
+#define DRV_VERSION    "0.08"
+#define DRV_RELDATE    "February 14, 2006"
 
 enum {
        MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
@@ -64,7 +64,8 @@ enum {
        MTHCA_FLAG_NO_LAM     = 1 << 5,
        MTHCA_FLAG_FMR        = 1 << 6,
        MTHCA_FLAG_MEMFREE    = 1 << 7,
-       MTHCA_FLAG_PCIE       = 1 << 8
+       MTHCA_FLAG_PCIE       = 1 << 8,
+       MTHCA_FLAG_SINAI_OPT  = 1 << 9
 };
 
 enum {
@@ -110,9 +111,17 @@ enum {
        MTHCA_OPCODE_INVALID        = 0xff
 };
 
+enum {
+       MTHCA_CMD_USE_EVENTS         = 1 << 0,
+       MTHCA_CMD_POST_DOORBELLS     = 1 << 1
+};
+
+enum {
+       MTHCA_CMD_NUM_DBELL_DWORDS = 8
+};
+
 struct mthca_cmd {
        struct pci_pool          *pool;
-       int                       use_events;
        struct mutex              hcr_mutex;
        struct semaphore          poll_sem;
        struct semaphore          event_sem;
@@ -121,6 +130,9 @@ struct mthca_cmd {
        int                       free_head;
        struct mthca_cmd_context *context;
        u16                       token_mask;
+       u32                       flags;
+       void __iomem             *dbell_map;
+       u16                       dbell_offsets[MTHCA_CMD_NUM_DBELL_DWORDS];
 };
 
 struct mthca_limits {
@@ -470,12 +482,16 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn,
                    enum ib_event_type event_type);
 void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn,
                    struct mthca_srq *srq);
+void mthca_cq_resize_copy_cqes(struct mthca_cq *cq);
+int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent);
+void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe);
 
 int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
                    struct ib_srq_attr *attr, struct mthca_srq *srq);
 void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq);
 int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
                     enum ib_srq_attr_mask attr_mask);
+int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
 void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
                     enum ib_event_type event_type);
 void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr);
@@ -486,6 +502,8 @@ int mthca_arbel_post_srq_recv(struct ib_srq *srq, struct ib_recv_wr *wr,
 
 void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
                    enum ib_event_type event_type);
+int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+                  struct ib_qp_init_attr *qp_init_attr);
 int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
 int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                          struct ib_send_wr **bad_wr);
@@ -495,8 +513,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                          struct ib_send_wr **bad_wr);
 int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                             struct ib_recv_wr **bad_wr);
-int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
-                      int index, int *dbd, __be32 *new_wqe);
+void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
+                       int index, int *dbd, __be32 *new_wqe);
 int mthca_alloc_qp(struct mthca_dev *dev,
                   struct mthca_pd *pd,
                   struct mthca_cq *send_cq,
@@ -522,6 +540,7 @@ int mthca_create_ah(struct mthca_dev *dev,
 int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah);
 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
                  struct ib_ud_header *header);
+int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr);
 int mthca_ah_grh_present(struct mthca_ah *ah);
 
 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
index 2eabb27..cbdc348 100644 (file)
@@ -497,7 +497,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 
        eq->dev  = dev;
        eq->nent = roundup_pow_of_two(max(nent, 2));
-       npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
+       npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
 
        eq->page_list = kmalloc(npages * sizeof *eq->page_list,
                                GFP_KERNEL);
@@ -825,7 +825,7 @@ void __devexit mthca_unmap_eq_icm(struct mthca_dev *dev)
 {
        u8 status;
 
-       mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, PAGE_SIZE / 4096, &status);
+       mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, 1, &status);
        pci_unmap_page(dev->pdev, dev->eq_table.icm_dma, PAGE_SIZE,
                       PCI_DMA_BIDIRECTIONAL);
        __free_page(dev->eq_table.icm_page);
@@ -928,7 +928,7 @@ int __devinit mthca_init_eq_table(struct mthca_dev *dev)
                mthca_warn(dev, "MAP_EQ for cmd EQ %d returned status 0x%02x\n",
                           dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status);
 
-       for (i = 0; i < MTHCA_EQ_CMD; ++i)
+       for (i = 0; i < MTHCA_NUM_EQ; ++i)
                if (mthca_is_memfree(dev))
                        arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);
                else
index 1229c60..4ace6a3 100644 (file)
@@ -109,6 +109,19 @@ static void smp_snoop(struct ib_device *ibdev,
        }
 }
 
+static void node_desc_override(struct ib_device *dev,
+                              struct ib_mad *mad)
+{
+       if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+            mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
+           mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
+           mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
+               mutex_lock(&to_mdev(dev)->cap_mask_mutex);
+               memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+               mutex_unlock(&to_mdev(dev)->cap_mask_mutex);
+       }
+}
+
 static void forward_trap(struct mthca_dev *dev,
                         u8 port_num,
                         struct ib_mad *mad)
@@ -207,8 +220,10 @@ int mthca_process_mad(struct ib_device *ibdev,
                return IB_MAD_RESULT_FAILURE;
        }
 
-       if (!out_mad->mad_hdr.status)
+       if (!out_mad->mad_hdr.status) {
                smp_snoop(ibdev, port_num, in_mad);
+               node_desc_override(ibdev, out_mad);
+       }
 
        /* set return bit in status of directed route responses */
        if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
index 9c849d2..266f347 100644 (file)
@@ -935,13 +935,19 @@ enum {
 
 static struct {
        u64 latest_fw;
-       int is_memfree;
-       int is_pcie;
+       u32 flags;
 } mthca_hca_table[] = {
-       [TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 3, 3), .is_memfree = 0, .is_pcie = 0 },
-       [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 0), .is_memfree = 0, .is_pcie = 1 },
-       [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0), .is_memfree = 1, .is_pcie = 1 },
-       [SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 0, 1), .is_memfree = 1, .is_pcie = 1 }
+       [TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 4, 0),
+                          .flags     = 0 },
+       [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 400),
+                          .flags     = MTHCA_FLAG_PCIE },
+       [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0),
+                          .flags     = MTHCA_FLAG_MEMFREE |
+                                       MTHCA_FLAG_PCIE },
+       [SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 0, 800),
+                          .flags     = MTHCA_FLAG_MEMFREE |
+                                       MTHCA_FLAG_PCIE    |
+                                       MTHCA_FLAG_SINAI_OPT }
 };
 
 static int __devinit mthca_init_one(struct pci_dev *pdev,
@@ -1031,12 +1037,9 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
 
        mdev->pdev = pdev;
 
+       mdev->mthca_flags = mthca_hca_table[id->driver_data].flags;
        if (ddr_hidden)
                mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;
-       if (mthca_hca_table[id->driver_data].is_memfree)
-               mdev->mthca_flags |= MTHCA_FLAG_MEMFREE;
-       if (mthca_hca_table[id->driver_data].is_pcie)
-               mdev->mthca_flags |= MTHCA_FLAG_PCIE;
 
        /*
         * Now reset the HCA before we touch the PCI capabilities or
index 321f11e..9965bda 100644 (file)
@@ -187,7 +187,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 
        for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
                if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
-                       mthca_dbg(dev, "QP %06x already a member of MGM\n", 
+                       mthca_dbg(dev, "QP %06x already a member of MGM\n",
                                  ibqp->qp_num);
                        err = 0;
                        goto out;
index d709cb1..15cc2f6 100644 (file)
@@ -202,7 +202,8 @@ void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int o
 
        if (--table->icm[i]->refcount == 0) {
                mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
-                               MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+                               MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+                               &status);
                mthca_free_icm(dev, table->icm[i]);
                table->icm[i] = NULL;
        }
@@ -336,7 +337,8 @@ err:
        for (i = 0; i < num_icm; ++i)
                if (table->icm[i]) {
                        mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE,
-                                       MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+                                       MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+                                       &status);
                        mthca_free_icm(dev, table->icm[i]);
                }
 
@@ -353,7 +355,8 @@ void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table)
        for (i = 0; i < table->num_icm; ++i)
                if (table->icm[i]) {
                        mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
-                                       MTHCA_TABLE_CHUNK_SIZE >> 12, &status);
+                                       MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
+                                       &status);
                        mthca_free_icm(dev, table->icm[i]);
                }
 
@@ -364,7 +367,7 @@ static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int pag
 {
        return dev->uar_table.uarc_base +
                uar->index * dev->uar_table.uarc_size +
-               page * 4096;
+               page * MTHCA_ICM_PAGE_SIZE;
 }
 
 int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
@@ -401,7 +404,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
        if (ret < 0)
                goto out;
 
-       db_tab->page[i].mem.length = 4096;
+       db_tab->page[i].mem.length = MTHCA_ICM_PAGE_SIZE;
        db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
 
        ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
@@ -455,7 +458,7 @@ struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev)
        if (!mthca_is_memfree(dev))
                return NULL;
 
-       npages = dev->uar_table.uarc_size / 4096;
+       npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE;
        db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL);
        if (!db_tab)
                return ERR_PTR(-ENOMEM);
@@ -478,7 +481,7 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
        if (!mthca_is_memfree(dev))
                return;
 
-       for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) {
+       for (i = 0; i < dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; ++i) {
                if (db_tab->page[i].uvirt) {
                        mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
                        pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
@@ -551,20 +554,20 @@ int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type,
        page = dev->db_tab->page + end;
 
 alloc:
-       page->db_rec = dma_alloc_coherent(&dev->pdev->dev, 4096,
+       page->db_rec = dma_alloc_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
                                          &page->mapping, GFP_KERNEL);
        if (!page->db_rec) {
                ret = -ENOMEM;
                goto out;
        }
-       memset(page->db_rec, 0, 4096);
+       memset(page->db_rec, 0, MTHCA_ICM_PAGE_SIZE);
 
        ret = mthca_MAP_ICM_page(dev, page->mapping,
                                 mthca_uarc_virt(dev, &dev->driver_uar, i), &status);
        if (!ret && status)
                ret = -EINVAL;
        if (ret) {
-               dma_free_coherent(&dev->pdev->dev, 4096,
+               dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
                                  page->db_rec, page->mapping);
                goto out;
        }
@@ -612,7 +615,7 @@ void mthca_free_db(struct mthca_dev *dev, int type, int db_index)
            i >= dev->db_tab->max_group1 - 1) {
                mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
 
-               dma_free_coherent(&dev->pdev->dev, 4096,
+               dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
                                  page->db_rec, page->mapping);
                page->db_rec = NULL;
 
@@ -640,7 +643,7 @@ int mthca_init_db_tab(struct mthca_dev *dev)
 
        mutex_init(&dev->db_tab->mutex);
 
-       dev->db_tab->npages     = dev->uar_table.uarc_size / 4096;
+       dev->db_tab->npages     = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE;
        dev->db_tab->max_group1 = 0;
        dev->db_tab->min_group2 = dev->db_tab->npages - 1;
 
@@ -681,7 +684,7 @@ void mthca_cleanup_db_tab(struct mthca_dev *dev)
 
                mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
 
-               dma_free_coherent(&dev->pdev->dev, 4096,
+               dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE,
                                  dev->db_tab->page[i].db_rec,
                                  dev->db_tab->page[i].mapping);
        }
index 36f1141..6d42947 100644 (file)
        ((256 - sizeof (struct list_head) - 2 * sizeof (int)) /         \
         (sizeof (struct scatterlist)))
 
+enum {
+       MTHCA_ICM_PAGE_SHIFT    = 12,
+       MTHCA_ICM_PAGE_SIZE     = 1 << MTHCA_ICM_PAGE_SHIFT,
+       MTHCA_DB_REC_PER_PAGE   = MTHCA_ICM_PAGE_SIZE / 8
+};
+
 struct mthca_icm_chunk {
        struct list_head   list;
        int                npages;
@@ -131,10 +137,6 @@ static inline unsigned long mthca_icm_size(struct mthca_icm_iter *iter)
        return sg_dma_len(&iter->chunk->mem[iter->page_idx]);
 }
 
-enum {
-       MTHCA_DB_REC_PER_PAGE = 4096 / 8
-};
-
 struct mthca_db_page {
        DECLARE_BITMAP(used, MTHCA_DB_REC_PER_PAGE);
        __be64    *db_rec;
index e995e2a..698b621 100644 (file)
@@ -76,6 +76,8 @@ struct mthca_mpt_entry {
 #define MTHCA_MPT_STATUS_SW 0xF0
 #define MTHCA_MPT_STATUS_HW 0x00
 
+#define SINAI_FMR_KEY_INC 0x1000000
+
 /*
  * Buddy allocator for MTT segments (currently not very efficient
  * since it doesn't keep a free list and just searches linearly
@@ -330,6 +332,14 @@ static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
                return tavor_key_to_hw_index(key);
 }
 
+static inline u32 adjust_key(struct mthca_dev *dev, u32 key)
+{
+       if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+               return ((key << 20) & 0x800000) | (key & 0x7fffff);
+       else
+               return key;
+}
+
 int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
                   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
 {
@@ -340,13 +350,12 @@ int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
        int err;
        u8 status;
 
-       might_sleep();
-
        WARN_ON(buffer_size_shift >= 32);
 
        key = mthca_alloc(&dev->mr_table.mpt_alloc);
        if (key == -1)
                return -ENOMEM;
+       key = adjust_key(dev, key);
        mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
 
        if (mthca_is_memfree(dev)) {
@@ -467,8 +476,6 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
        int err;
        u8 status;
 
-       might_sleep();
-
        err = mthca_HW2SW_MPT(dev, NULL,
                              key_to_hw_index(dev, mr->ibmr.lkey) &
                              (dev->limits.num_mpts - 1),
@@ -495,9 +502,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
        int err = -ENOMEM;
        int i;
 
-       might_sleep();
-
-       if (mr->attr.page_size < 12 || mr->attr.page_size >= 32)
+       if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32)
                return -EINVAL;
 
        /* For Arbel, all MTTs must fit in the same page. */
@@ -510,6 +515,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
        key = mthca_alloc(&dev->mr_table.mpt_alloc);
        if (key == -1)
                return -ENOMEM;
+       key = adjust_key(dev, key);
 
        idx = key & (dev->limits.num_mpts - 1);
        mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
@@ -523,7 +529,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                BUG_ON(!mr->mem.arbel.mpt);
        } else
                mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
-                       sizeof *(mr->mem.tavor.mpt) * idx;
+                       sizeof *(mr->mem.tavor.mpt) * idx;
 
        mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
        if (IS_ERR(mr->mtt))
@@ -549,7 +555,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                                       MTHCA_MPT_FLAG_REGION      |
                                       access);
 
-       mpt_entry->page_size = cpu_to_be32(mr->attr.page_size - 12);
+       mpt_entry->page_size = cpu_to_be32(mr->attr.page_shift - 12);
        mpt_entry->key       = cpu_to_be32(key);
        mpt_entry->pd        = cpu_to_be32(pd);
        memset(&mpt_entry->start, 0,
@@ -617,7 +623,7 @@ static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list,
        if (list_len > fmr->attr.max_pages)
                return -EINVAL;
 
-       page_mask = (1 << fmr->attr.page_size) - 1;
+       page_mask = (1 << fmr->attr.page_shift) - 1;
 
        /* We are getting page lists, so va must be page aligned. */
        if (iova & page_mask)
@@ -665,7 +671,7 @@ int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
        }
 
        mpt_entry.lkey   = cpu_to_be32(key);
-       mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+       mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
        mpt_entry.start  = cpu_to_be64(iova);
 
        __raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key);
@@ -693,7 +699,10 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
        ++fmr->maps;
 
        key = arbel_key_to_hw_index(fmr->ibmr.lkey);
-       key += dev->limits.num_mpts;
+       if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+               key += SINAI_FMR_KEY_INC;
+       else
+               key += dev->limits.num_mpts;
        fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
 
        *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
@@ -706,7 +715,7 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
 
        fmr->mem.arbel.mpt->key    = cpu_to_be32(key);
        fmr->mem.arbel.mpt->lkey   = cpu_to_be32(key);
-       fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_size));
+       fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
        fmr->mem.arbel.mpt->start  = cpu_to_be64(iova);
 
        wmb();
@@ -766,6 +775,9 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
        else
                dev->mthca_flags |= MTHCA_FLAG_FMR;
 
+       if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
+               mthca_dbg(dev, "Memory key throughput optimization activated.\n");
+
        err = mthca_buddy_init(&dev->mr_table.mtt_buddy,
                               fls(dev->limits.num_mtt_segs - 1));
 
@@ -785,7 +797,7 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
                }
 
                dev->mr_table.tavor_fmr.mpt_base =
-                       ioremap(dev->mr_table.mpt_base,
+                       ioremap(dev->mr_table.mpt_base,
                                (1 << i) * sizeof (struct mthca_mpt_entry));
 
                if (!dev->mr_table.tavor_fmr.mpt_base) {
@@ -813,7 +825,7 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
                        goto err_reserve_fmr;
 
                dev->mr_table.fmr_mtt_buddy =
-                       &dev->mr_table.tavor_fmr.mtt_buddy;
+                       &dev->mr_table.tavor_fmr.mtt_buddy;
        } else
                dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy;
 
index 3dbf06a..105fc5f 100644 (file)
@@ -43,8 +43,6 @@ int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd)
 {
        int err = 0;
 
-       might_sleep();
-
        pd->privileged = privileged;
 
        atomic_set(&pd->sqp_count, 0);
@@ -66,7 +64,6 @@ int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd)
 
 void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd)
 {
-       might_sleep();
        if (pd->privileged)
                mthca_free_mr(dev, &pd->ntmr);
        mthca_free(&dev->pd_table.alloc, pd->pd_num);
index 08a9093..58d44aa 100644 (file)
@@ -152,7 +152,7 @@ u64 mthca_make_profile(struct mthca_dev *dev,
                }
                if (total_size > mem_avail) {
                        mthca_err(dev, "Profile requires 0x%llx bytes; "
-                                 "won't in 0x%llx bytes of context memory.\n",
+                                 "won't fit in 0x%llx bytes of context memory.\n",
                                  (unsigned long long) total_size,
                                  (unsigned long long) mem_avail);
                        kfree(profile);
@@ -262,6 +262,14 @@ u64 mthca_make_profile(struct mthca_dev *dev,
         */
        dev->limits.num_pds = MTHCA_NUM_PDS;
 
+       if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT &&
+           init_hca->log_mpt_sz > 23) {
+               mthca_warn(dev, "MPT table too large (requested size 2^%d >= 2^24)\n",
+                          init_hca->log_mpt_sz);
+               mthca_warn(dev, "Disabling memory key throughput optimization.\n");
+               dev->mthca_flags &= ~MTHCA_FLAG_SINAI_OPT;
+       }
+
        /*
         * For Tavor, FMRs use ioremapped PCI memory. For 32 bit
         * systems it may use too much vmalloc space to map all MTT
index e88e39a..2c250bc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
@@ -108,12 +108,12 @@ static int mthca_query_device(struct ib_device *ibdev,
        props->max_srq_wr          = mdev->limits.max_srq_wqes;
        props->max_srq_sge         = mdev->limits.max_sg;
        props->local_ca_ack_delay  = mdev->limits.local_ca_ack_delay;
-       props->atomic_cap          = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? 
+       props->atomic_cap          = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ?
                                        IB_ATOMIC_HCA : IB_ATOMIC_NONE;
        props->max_pkeys           = mdev->limits.pkey_table_len;
        props->max_mcast_grp       = mdev->limits.num_mgms + mdev->limits.num_amgms;
        props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;
-       props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * 
+       props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
                                           props->max_mcast_grp;
 
        err = 0;
@@ -176,6 +176,23 @@ static int mthca_query_port(struct ib_device *ibdev,
        return err;
 }
 
+static int mthca_modify_device(struct ib_device *ibdev,
+                              int mask,
+                              struct ib_device_modify *props)
+{
+       if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
+               return -EOPNOTSUPP;
+
+       if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
+               if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
+                       return -ERESTARTSYS;
+               memcpy(ibdev->node_desc, props->node_desc, 64);
+               mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
+       }
+
+       return 0;
+}
+
 static int mthca_modify_port(struct ib_device *ibdev,
                             u8 port, int port_modify_mask,
                             struct ib_port_modify *props)
@@ -669,9 +686,9 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
        }
 
        if (context) {
-               cq->mr.ibmr.lkey    = ucmd.lkey;
-               cq->set_ci_db_index = ucmd.set_db_index;
-               cq->arm_db_index    = ucmd.arm_db_index;
+               cq->buf.mr.ibmr.lkey = ucmd.lkey;
+               cq->set_ci_db_index  = ucmd.set_db_index;
+               cq->arm_db_index     = ucmd.arm_db_index;
        }
 
        for (nent = 1; nent <= entries; nent <<= 1)
@@ -689,6 +706,8 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
                goto err_free;
        }
 
+       cq->resize_buf = NULL;
+
        return &cq->ibcq;
 
 err_free:
@@ -707,6 +726,121 @@ err_unmap_set:
        return ERR_PTR(err);
 }
 
+static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq,
+                                 int entries)
+{
+       int ret;
+
+       spin_lock_irq(&cq->lock);
+       if (cq->resize_buf) {
+               ret = -EBUSY;
+               goto unlock;
+       }
+
+       cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);
+       if (!cq->resize_buf) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+
+       cq->resize_buf->state = CQ_RESIZE_ALLOC;
+
+       ret = 0;
+
+unlock:
+       spin_unlock_irq(&cq->lock);
+
+       if (ret)
+               return ret;
+
+       ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries);
+       if (ret) {
+               spin_lock_irq(&cq->lock);
+               kfree(cq->resize_buf);
+               cq->resize_buf = NULL;
+               spin_unlock_irq(&cq->lock);
+               return ret;
+       }
+
+       cq->resize_buf->cqe = entries - 1;
+
+       spin_lock_irq(&cq->lock);
+       cq->resize_buf->state = CQ_RESIZE_READY;
+       spin_unlock_irq(&cq->lock);
+
+       return 0;
+}
+
+static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+{
+       struct mthca_dev *dev = to_mdev(ibcq->device);
+       struct mthca_cq *cq = to_mcq(ibcq);
+       struct mthca_resize_cq ucmd;
+       u32 lkey;
+       u8 status;
+       int ret;
+
+       if (entries < 1 || entries > dev->limits.max_cqes)
+               return -EINVAL;
+
+       entries = roundup_pow_of_two(entries + 1);
+       if (entries == ibcq->cqe + 1)
+               return 0;
+
+       if (cq->is_kernel) {
+               ret = mthca_alloc_resize_buf(dev, cq, entries);
+               if (ret)
+                       return ret;
+               lkey = cq->resize_buf->buf.mr.ibmr.lkey;
+       } else {
+               if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+                       return -EFAULT;
+               lkey = ucmd.lkey;
+       }
+
+       ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, long_log2(entries), &status);
+       if (status)
+               ret = -EINVAL;
+
+       if (ret) {
+               if (cq->resize_buf) {
+                       mthca_free_cq_buf(dev, &cq->resize_buf->buf,
+                                         cq->resize_buf->cqe);
+                       kfree(cq->resize_buf);
+                       spin_lock_irq(&cq->lock);
+                       cq->resize_buf = NULL;
+                       spin_unlock_irq(&cq->lock);
+               }
+               return ret;
+       }
+
+       if (cq->is_kernel) {
+               struct mthca_cq_buf tbuf;
+               int tcqe;
+
+               spin_lock_irq(&cq->lock);
+               if (cq->resize_buf->state == CQ_RESIZE_READY) {
+                       mthca_cq_resize_copy_cqes(cq);
+                       tbuf         = cq->buf;
+                       tcqe         = cq->ibcq.cqe;
+                       cq->buf      = cq->resize_buf->buf;
+                       cq->ibcq.cqe = cq->resize_buf->cqe;
+               } else {
+                       tbuf = cq->resize_buf->buf;
+                       tcqe = cq->resize_buf->cqe;
+               }
+
+               kfree(cq->resize_buf);
+               cq->resize_buf = NULL;
+               spin_unlock_irq(&cq->lock);
+
+               mthca_free_cq_buf(dev, &tbuf, tcqe);
+       } else
+               ibcq->cqe = entries - 1;
+
+       return 0;
+}
+
 static int mthca_destroy_cq(struct ib_cq *cq)
 {
        if (cq->uobject) {
@@ -1070,6 +1204,20 @@ static int mthca_init_node_data(struct mthca_dev *dev)
                goto out;
 
        init_query_mad(in_mad);
+       in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
+
+       err = mthca_MAD_IFC(dev, 1, 1,
+                           1, NULL, NULL, in_mad, out_mad,
+                           &status);
+       if (err)
+               goto out;
+       if (status) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+
        in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
 
        err = mthca_MAD_IFC(dev, 1, 1,
@@ -1113,14 +1261,17 @@ int mthca_register_device(struct mthca_dev *dev)
                (1ull << IB_USER_VERBS_CMD_DEREG_MR)            |
                (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
                (1ull << IB_USER_VERBS_CMD_CREATE_CQ)           |
+               (1ull << IB_USER_VERBS_CMD_RESIZE_CQ)           |
                (1ull << IB_USER_VERBS_CMD_DESTROY_CQ)          |
                (1ull << IB_USER_VERBS_CMD_CREATE_QP)           |
+               (1ull << IB_USER_VERBS_CMD_QUERY_QP)            |
                (1ull << IB_USER_VERBS_CMD_MODIFY_QP)           |
                (1ull << IB_USER_VERBS_CMD_DESTROY_QP)          |
                (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)        |
                (1ull << IB_USER_VERBS_CMD_DETACH_MCAST)        |
                (1ull << IB_USER_VERBS_CMD_CREATE_SRQ)          |
                (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)          |
+               (1ull << IB_USER_VERBS_CMD_QUERY_SRQ)           |
                (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
        dev->ib_dev.node_type            = IB_NODE_CA;
        dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
@@ -1128,6 +1279,7 @@ int mthca_register_device(struct mthca_dev *dev)
        dev->ib_dev.class_dev.dev        = &dev->pdev->dev;
        dev->ib_dev.query_device         = mthca_query_device;
        dev->ib_dev.query_port           = mthca_query_port;
+       dev->ib_dev.modify_device        = mthca_modify_device;
        dev->ib_dev.modify_port          = mthca_modify_port;
        dev->ib_dev.query_pkey           = mthca_query_pkey;
        dev->ib_dev.query_gid            = mthca_query_gid;
@@ -1137,11 +1289,13 @@ int mthca_register_device(struct mthca_dev *dev)
        dev->ib_dev.alloc_pd             = mthca_alloc_pd;
        dev->ib_dev.dealloc_pd           = mthca_dealloc_pd;
        dev->ib_dev.create_ah            = mthca_ah_create;
+       dev->ib_dev.query_ah             = mthca_ah_query;
        dev->ib_dev.destroy_ah           = mthca_ah_destroy;
 
        if (dev->mthca_flags & MTHCA_FLAG_SRQ) {
                dev->ib_dev.create_srq           = mthca_create_srq;
-               dev->ib_dev.modify_srq           = mthca_modify_srq;
+               dev->ib_dev.modify_srq           = mthca_modify_srq;
+               dev->ib_dev.query_srq            = mthca_query_srq;
                dev->ib_dev.destroy_srq          = mthca_destroy_srq;
 
                if (mthca_is_memfree(dev))
@@ -1152,8 +1306,10 @@ int mthca_register_device(struct mthca_dev *dev)
 
        dev->ib_dev.create_qp            = mthca_create_qp;
        dev->ib_dev.modify_qp            = mthca_modify_qp;
+       dev->ib_dev.query_qp             = mthca_query_qp;
        dev->ib_dev.destroy_qp           = mthca_destroy_qp;
        dev->ib_dev.create_cq            = mthca_create_cq;
+       dev->ib_dev.resize_cq            = mthca_resize_cq;
        dev->ib_dev.destroy_cq           = mthca_destroy_cq;
        dev->ib_dev.poll_cq              = mthca_poll_cq;
        dev->ib_dev.get_dma_mr           = mthca_get_dma_mr;
index 1e73947..2e7f521 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -164,9 +164,11 @@ struct mthca_ah {
  * - wait_event until ref count is zero
  *
  * It is the consumer's responsibilty to make sure that no QP
- * operations (WQE posting or state modification) are pending when the
+ * operations (WQE posting or state modification) are pending when a
  * QP is destroyed.  Also, the consumer must make sure that calls to
- * qp_modify are serialized.
+ * qp_modify are serialized.  Similarly, the consumer is responsible
+ * for ensuring that no CQ resize operations are pending when a CQ
+ * is destroyed.
  *
  * Possible optimizations (wait for profile data to see if/where we
  * have locks bouncing between CPUs):
@@ -176,25 +178,40 @@ struct mthca_ah {
  *   send queue and one for the receive queue)
  */
 
+struct mthca_cq_buf {
+       union mthca_buf         queue;
+       struct mthca_mr         mr;
+       int                     is_direct;
+};
+
+struct mthca_cq_resize {
+       struct mthca_cq_buf     buf;
+       int                     cqe;
+       enum {
+               CQ_RESIZE_ALLOC,
+               CQ_RESIZE_READY,
+               CQ_RESIZE_SWAPPED
+       }                       state;
+};
+
 struct mthca_cq {
-       struct ib_cq           ibcq;
-       spinlock_t             lock;
-       atomic_t               refcount;
-       int                    cqn;
-       u32                    cons_index;
-       int                    is_direct;
-       int                    is_kernel;
+       struct ib_cq            ibcq;
+       spinlock_t              lock;
+       atomic_t                refcount;
+       int                     cqn;
+       u32                     cons_index;
+       struct mthca_cq_buf     buf;
+       struct mthca_cq_resize *resize_buf;
+       int                     is_kernel;
 
        /* Next fields are Arbel only */
-       int                    set_ci_db_index;
-       __be32                *set_ci_db;
-       int                    arm_db_index;
-       __be32                *arm_db;
-       int                    arm_sn;
+       int                     set_ci_db_index;
+       __be32                 *set_ci_db;
+       int                     arm_db_index;
+       __be32                 *arm_db;
+       int                     arm_sn;
 
-       union mthca_buf        queue;
-       struct mthca_mr        mr;
-       wait_queue_head_t      wait;
+       wait_queue_head_t       wait;
 };
 
 struct mthca_srq {
index fba608e..f673c46 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Cisco Systems. All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -286,207 +286,6 @@ static int to_mthca_st(int transport)
        }
 }
 
-static const struct {
-       int trans;
-       u32 req_param[NUM_TRANS];
-       u32 opt_param[NUM_TRANS];
-} state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
-       [IB_QPS_RESET] = {
-               [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-               [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-               [IB_QPS_INIT]  = {
-                       .trans = MTHCA_TRANS_RST2INIT,
-                       .req_param = {
-                               [UD]  = (IB_QP_PKEY_INDEX |
-                                        IB_QP_PORT       |
-                                        IB_QP_QKEY),
-                               [UC]  = (IB_QP_PKEY_INDEX |
-                                        IB_QP_PORT       |
-                                        IB_QP_ACCESS_FLAGS),
-                               [RC]  = (IB_QP_PKEY_INDEX |
-                                        IB_QP_PORT       |
-                                        IB_QP_ACCESS_FLAGS),
-                               [MLX] = (IB_QP_PKEY_INDEX |
-                                        IB_QP_QKEY),
-                       },
-                       /* bug-for-bug compatibility with VAPI: */
-                       .opt_param = {
-                               [MLX] = IB_QP_PORT
-                       }
-               },
-       },
-       [IB_QPS_INIT]  = {
-               [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-               [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-               [IB_QPS_INIT]  = {
-                       .trans = MTHCA_TRANS_INIT2INIT,
-                       .opt_param = {
-                               [UD]  = (IB_QP_PKEY_INDEX |
-                                        IB_QP_PORT       |
-                                        IB_QP_QKEY),
-                               [UC]  = (IB_QP_PKEY_INDEX |
-                                        IB_QP_PORT       |
-                                        IB_QP_ACCESS_FLAGS),
-                               [RC]  = (IB_QP_PKEY_INDEX |
-                                        IB_QP_PORT       |
-                                        IB_QP_ACCESS_FLAGS),
-                               [MLX] = (IB_QP_PKEY_INDEX |
-                                        IB_QP_QKEY),
-                       }
-               },
-               [IB_QPS_RTR]   = {
-                       .trans = MTHCA_TRANS_INIT2RTR,
-                       .req_param = {
-                               [UC]  = (IB_QP_AV                  |
-                                        IB_QP_PATH_MTU            |
-                                        IB_QP_DEST_QPN            |
-                                        IB_QP_RQ_PSN),
-                               [RC]  = (IB_QP_AV                  |
-                                        IB_QP_PATH_MTU            |
-                                        IB_QP_DEST_QPN            |
-                                        IB_QP_RQ_PSN              |
-                                        IB_QP_MAX_DEST_RD_ATOMIC  |
-                                        IB_QP_MIN_RNR_TIMER),
-                       },
-                       .opt_param = {
-                               [UD]  = (IB_QP_PKEY_INDEX |
-                                        IB_QP_QKEY),
-                               [UC]  = (IB_QP_ALT_PATH     |
-                                        IB_QP_ACCESS_FLAGS |
-                                        IB_QP_PKEY_INDEX),
-                               [RC]  = (IB_QP_ALT_PATH     |
-                                        IB_QP_ACCESS_FLAGS |
-                                        IB_QP_PKEY_INDEX),
-                               [MLX] = (IB_QP_PKEY_INDEX |
-                                        IB_QP_QKEY),
-                       }
-               }
-       },
-       [IB_QPS_RTR]   = {
-               [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-               [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-               [IB_QPS_RTS]   = {
-                       .trans = MTHCA_TRANS_RTR2RTS,
-                       .req_param = {
-                               [UD]  = IB_QP_SQ_PSN,
-                               [UC]  = IB_QP_SQ_PSN,
-                               [RC]  = (IB_QP_TIMEOUT           |
-                                        IB_QP_RETRY_CNT         |
-                                        IB_QP_RNR_RETRY         |
-                                        IB_QP_SQ_PSN            |
-                                        IB_QP_MAX_QP_RD_ATOMIC),
-                               [MLX] = IB_QP_SQ_PSN,
-                       },
-                       .opt_param = {
-                               [UD]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_QKEY),
-                               [UC]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_ALT_PATH              |
-                                        IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_PATH_MIG_STATE),
-                               [RC]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_ALT_PATH              |
-                                        IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_MIN_RNR_TIMER         |
-                                        IB_QP_PATH_MIG_STATE),
-                               [MLX] = (IB_QP_CUR_STATE             |
-                                        IB_QP_QKEY),
-                       }
-               }
-       },
-       [IB_QPS_RTS]   = {
-               [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-               [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-               [IB_QPS_RTS]   = {
-                       .trans = MTHCA_TRANS_RTS2RTS,
-                       .opt_param = {
-                               [UD]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_QKEY),
-                               [UC]  = (IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_ALT_PATH              |
-                                        IB_QP_PATH_MIG_STATE),
-                               [RC]  = (IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_ALT_PATH              |
-                                        IB_QP_PATH_MIG_STATE        |
-                                        IB_QP_MIN_RNR_TIMER),
-                               [MLX] = (IB_QP_CUR_STATE             |
-                                        IB_QP_QKEY),
-                       }
-               },
-               [IB_QPS_SQD]   = {
-                       .trans = MTHCA_TRANS_RTS2SQD,
-               },
-       },
-       [IB_QPS_SQD]   = {
-               [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-               [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-               [IB_QPS_RTS]   = {
-                       .trans = MTHCA_TRANS_SQD2RTS,
-                       .opt_param = {
-                               [UD]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_QKEY),
-                               [UC]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_ALT_PATH              |
-                                        IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_PATH_MIG_STATE),
-                               [RC]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_ALT_PATH              |
-                                        IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_MIN_RNR_TIMER         |
-                                        IB_QP_PATH_MIG_STATE),
-                               [MLX] = (IB_QP_CUR_STATE             |
-                                        IB_QP_QKEY),
-                       }
-               },
-               [IB_QPS_SQD]   = {
-                       .trans = MTHCA_TRANS_SQD2SQD,
-                       .opt_param = {
-                               [UD]  = (IB_QP_PKEY_INDEX            |
-                                        IB_QP_QKEY),
-                               [UC]  = (IB_QP_AV                    |
-                                        IB_QP_CUR_STATE             |
-                                        IB_QP_ALT_PATH              |
-                                        IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_PKEY_INDEX            |
-                                        IB_QP_PATH_MIG_STATE),
-                               [RC]  = (IB_QP_AV                    |
-                                        IB_QP_TIMEOUT               |
-                                        IB_QP_RETRY_CNT             |
-                                        IB_QP_RNR_RETRY             |
-                                        IB_QP_MAX_QP_RD_ATOMIC      |
-                                        IB_QP_MAX_DEST_RD_ATOMIC    |
-                                        IB_QP_CUR_STATE             |
-                                        IB_QP_ALT_PATH              |
-                                        IB_QP_ACCESS_FLAGS          |
-                                        IB_QP_PKEY_INDEX            |
-                                        IB_QP_MIN_RNR_TIMER         |
-                                        IB_QP_PATH_MIG_STATE),
-                               [MLX] = (IB_QP_PKEY_INDEX            |
-                                        IB_QP_QKEY),
-                       }
-               }
-       },
-       [IB_QPS_SQE]   = {
-               [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-               [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR },
-               [IB_QPS_RTS]   = {
-                       .trans = MTHCA_TRANS_SQERR2RTS,
-                       .opt_param = {
-                               [UD]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_QKEY),
-                               [UC]  = (IB_QP_CUR_STATE             |
-                                        IB_QP_ACCESS_FLAGS),
-                               [MLX] = (IB_QP_CUR_STATE             |
-                                        IB_QP_QKEY),
-                       }
-               }
-       },
-       [IB_QPS_ERR] = {
-               [IB_QPS_RESET] = { .trans = MTHCA_TRANS_ANY2RST },
-               [IB_QPS_ERR] = { .trans = MTHCA_TRANS_ANY2ERR }
-       }
-};
-
 static void store_attrs(struct mthca_sqp *sqp, struct ib_qp_attr *attr,
                        int attr_mask)
 {
@@ -549,6 +348,141 @@ static __be32 get_hw_access_flags(struct mthca_qp *qp, struct ib_qp_attr *attr,
        return cpu_to_be32(hw_access_flags);
 }
 
+static inline enum ib_qp_state to_ib_qp_state(int mthca_state)
+{
+       switch (mthca_state) {
+       case MTHCA_QP_STATE_RST:      return IB_QPS_RESET;
+       case MTHCA_QP_STATE_INIT:     return IB_QPS_INIT;
+       case MTHCA_QP_STATE_RTR:      return IB_QPS_RTR;
+       case MTHCA_QP_STATE_RTS:      return IB_QPS_RTS;
+       case MTHCA_QP_STATE_DRAINING:
+       case MTHCA_QP_STATE_SQD:      return IB_QPS_SQD;
+       case MTHCA_QP_STATE_SQE:      return IB_QPS_SQE;
+       case MTHCA_QP_STATE_ERR:      return IB_QPS_ERR;
+       default:                      return -1;
+       }
+}
+
+static inline enum ib_mig_state to_ib_mig_state(int mthca_mig_state)
+{
+       switch (mthca_mig_state) {
+       case 0:  return IB_MIG_ARMED;
+       case 1:  return IB_MIG_REARM;
+       case 3:  return IB_MIG_MIGRATED;
+       default: return -1;
+       }
+}
+
+static int to_ib_qp_access_flags(int mthca_flags)
+{
+       int ib_flags = 0;
+
+       if (mthca_flags & MTHCA_QP_BIT_RRE)
+               ib_flags |= IB_ACCESS_REMOTE_READ;
+       if (mthca_flags & MTHCA_QP_BIT_RWE)
+               ib_flags |= IB_ACCESS_REMOTE_WRITE;
+       if (mthca_flags & MTHCA_QP_BIT_RAE)
+               ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
+
+       return ib_flags;
+}
+
+static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr,
+                               struct mthca_qp_path *path)
+{
+       memset(ib_ah_attr, 0, sizeof *path);
+       ib_ah_attr->port_num      = (be32_to_cpu(path->port_pkey) >> 24) & 0x3;
+       ib_ah_attr->dlid          = be16_to_cpu(path->rlid);
+       ib_ah_attr->sl            = be32_to_cpu(path->sl_tclass_flowlabel) >> 28;
+       ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f;
+       ib_ah_attr->static_rate   = path->static_rate & 0x7;
+       ib_ah_attr->ah_flags      = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
+       if (ib_ah_attr->ah_flags) {
+               ib_ah_attr->grh.sgid_index = path->mgid_index & (dev->limits.gid_table_len - 1);
+               ib_ah_attr->grh.hop_limit  = path->hop_limit;
+               ib_ah_attr->grh.traffic_class =
+                       (be32_to_cpu(path->sl_tclass_flowlabel) >> 20) & 0xff;
+               ib_ah_attr->grh.flow_label =
+                       be32_to_cpu(path->sl_tclass_flowlabel) & 0xfffff;
+               memcpy(ib_ah_attr->grh.dgid.raw,
+                       path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
+       }
+}
+
+int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+                  struct ib_qp_init_attr *qp_init_attr)
+{
+       struct mthca_dev *dev = to_mdev(ibqp->device);
+       struct mthca_qp *qp = to_mqp(ibqp);
+       int err;
+       struct mthca_mailbox *mailbox;
+       struct mthca_qp_param *qp_param;
+       struct mthca_qp_context *context;
+       int mthca_state;
+       u8 status;
+
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       err = mthca_QUERY_QP(dev, qp->qpn, 0, mailbox, &status);
+       if (err)
+               goto out;
+       if (status) {
+               mthca_warn(dev, "QUERY_QP returned status %02x\n", status);
+               err = -EINVAL;
+               goto out;
+       }
+
+       qp_param    = mailbox->buf;
+       context     = &qp_param->context;
+       mthca_state = be32_to_cpu(context->flags) >> 28;
+
+       qp_attr->qp_state            = to_ib_qp_state(mthca_state);
+       qp_attr->cur_qp_state        = qp_attr->qp_state;
+       qp_attr->path_mtu            = context->mtu_msgmax >> 5;
+       qp_attr->path_mig_state      =
+               to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3);
+       qp_attr->qkey                = be32_to_cpu(context->qkey);
+       qp_attr->rq_psn              = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff;
+       qp_attr->sq_psn              = be32_to_cpu(context->next_send_psn) & 0xffffff;
+       qp_attr->dest_qp_num         = be32_to_cpu(context->remote_qpn) & 0xffffff;
+       qp_attr->qp_access_flags     =
+               to_ib_qp_access_flags(be32_to_cpu(context->params2));
+       qp_attr->cap.max_send_wr     = qp->sq.max;
+       qp_attr->cap.max_recv_wr     = qp->rq.max;
+       qp_attr->cap.max_send_sge    = qp->sq.max_gs;
+       qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
+       qp_attr->cap.max_inline_data = qp->max_inline_data;
+
+       to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
+       to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
+
+       qp_attr->pkey_index     = be32_to_cpu(context->pri_path.port_pkey) & 0x7f;
+       qp_attr->alt_pkey_index = be32_to_cpu(context->alt_path.port_pkey) & 0x7f;
+
+       /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+       qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING;
+
+       qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7);
+
+       qp_attr->max_dest_rd_atomic =
+               1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
+       qp_attr->min_rnr_timer      =
+               (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
+       qp_attr->port_num           = qp_attr->ah_attr.port_num;
+       qp_attr->timeout            = context->pri_path.ackto >> 3;
+       qp_attr->retry_cnt          = (be32_to_cpu(context->params1) >> 16) & 0x7;
+       qp_attr->rnr_retry          = context->pri_path.rnr_retry >> 5;
+       qp_attr->alt_port_num       = qp_attr->alt_ah_attr.port_num;
+       qp_attr->alt_timeout        = context->alt_path.ackto >> 3;
+       qp_init_attr->cap           = qp_attr->cap;
+
+out:
+       mthca_free_mailbox(dev, mailbox);
+       return err;
+}
+
 static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path)
 {
        path->g_mylmc     = ah->src_path_bits & 0x7f;
@@ -559,9 +493,9 @@ static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path)
                path->g_mylmc   |= 1 << 7;
                path->mgid_index = ah->grh.sgid_index;
                path->hop_limit  = ah->grh.hop_limit;
-               path->sl_tclass_flowlabel = 
+               path->sl_tclass_flowlabel =
                        cpu_to_be32((ah->sl << 28)                |
-                                   (ah->grh.traffic_class << 20) | 
+                                   (ah->grh.traffic_class << 20) |
                                    (ah->grh.flow_label));
                memcpy(path->rgid, ah->grh.dgid.raw, 16);
        } else
@@ -576,18 +510,12 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        struct mthca_mailbox *mailbox;
        struct mthca_qp_param *qp_param;
        struct mthca_qp_context *qp_context;
-       u32 req_param, opt_param;
+       u32 sqd_event = 0;
        u8 status;
        int err;
 
        if (attr_mask & IB_QP_CUR_STATE) {
-               if (attr->cur_qp_state != IB_QPS_RTR &&
-                   attr->cur_qp_state != IB_QPS_RTS &&
-                   attr->cur_qp_state != IB_QPS_SQD &&
-                   attr->cur_qp_state != IB_QPS_SQE)
-                       return -EINVAL;
-               else
-                       cur_state = attr->cur_qp_state;
+               cur_state = attr->cur_qp_state;
        } else {
                spin_lock_irq(&qp->sq.lock);
                spin_lock(&qp->rq.lock);
@@ -596,44 +524,20 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                spin_unlock_irq(&qp->sq.lock);
        }
 
-       if (attr_mask & IB_QP_STATE) {
-               if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR)
-                       return -EINVAL;
-               new_state = attr->qp_state;
-       } else
-               new_state = cur_state;
-
-       if (state_table[cur_state][new_state].trans == MTHCA_TRANS_INVALID) {
-               mthca_dbg(dev, "Illegal QP transition "
-                         "%d->%d\n", cur_state, new_state);
-               return -EINVAL;
-       }
-
-       req_param = state_table[cur_state][new_state].req_param[qp->transport];
-       opt_param = state_table[cur_state][new_state].opt_param[qp->transport];
+       new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
 
-       if ((req_param & attr_mask) != req_param) {
-               mthca_dbg(dev, "QP transition "
-                         "%d->%d missing req attr 0x%08x\n",
-                         cur_state, new_state,
-                         req_param & ~attr_mask);
+       if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) {
+               mthca_dbg(dev, "Bad QP transition (transport %d) "
+                         "%d->%d with attr 0x%08x\n",
+                         qp->transport, cur_state, new_state,
+                         attr_mask);
                return -EINVAL;
        }
 
-       if (attr_mask & ~(req_param | opt_param | IB_QP_STATE)) {
-               mthca_dbg(dev, "QP transition (transport %d) "
-                         "%d->%d has extra attr 0x%08x\n",
-                         qp->transport,
-                         cur_state, new_state,
-                         attr_mask & ~(req_param | opt_param |
-                                                IB_QP_STATE));
-               return -EINVAL;
-       }
-
-       if ((attr_mask & IB_QP_PKEY_INDEX) && 
+       if ((attr_mask & IB_QP_PKEY_INDEX) &&
             attr->pkey_index >= dev->limits.pkey_table_len) {
-               mthca_dbg(dev, "PKey index (%u) too large. max is %d\n",
-                         attr->pkey_index,dev->limits.pkey_table_len-1); 
+               mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n",
+                         attr->pkey_index, dev->limits.pkey_table_len-1);
                return -EINVAL;
        }
 
@@ -733,7 +637,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        if (attr_mask & IB_QP_RNR_RETRY) {
                qp_context->alt_path.rnr_retry = qp_context->pri_path.rnr_retry =
                        attr->rnr_retry << 5;
-               qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY | 
+               qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY |
                                                        MTHCA_QP_OPTPAR_ALT_RNR_RETRY);
        }
 
@@ -748,14 +652,20 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
        }
 
        if (attr_mask & IB_QP_ALT_PATH) {
+               if (attr->alt_pkey_index >= dev->limits.pkey_table_len) {
+                       mthca_dbg(dev, "Alternate P_Key index (%u) too large. max is %d\n",
+                                 attr->alt_pkey_index, dev->limits.pkey_table_len-1);
+                       return -EINVAL;
+               }
+
                if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) {
-                       mthca_dbg(dev, "Alternate port number (%u) is invalid\n", 
+                       mthca_dbg(dev, "Alternate port number (%u) is invalid\n",
                                attr->alt_port_num);
                        return -EINVAL;
                }
 
                mthca_path_set(&attr->alt_ah_attr, &qp_context->alt_path);
-               qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | 
+               qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index |
                                                              attr->alt_port_num << 24);
                qp_context->alt_path.ackto = attr->alt_timeout << 3;
                qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ALT_ADDR_PATH);
@@ -841,11 +751,16 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
                qp_context->srqn = cpu_to_be32(1 << 24 |
                                               to_msrq(ibqp->srq)->srqn);
 
-       err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
-                             qp->qpn, 0, mailbox, 0, &status);
+       if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD  &&
+           attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY               &&
+           attr->en_sqd_async_notify)
+               sqd_event = 1 << 31;
+
+       err = mthca_MODIFY_QP(dev, cur_state, new_state, qp->qpn, 0,
+                             mailbox, sqd_event, &status);
        if (status) {
-               mthca_warn(dev, "modify QP %d returned status %02x.\n",
-                          state_table[cur_state][new_state].trans, status);
+               mthca_warn(dev, "modify QP %d->%d returned status %02x.\n",
+                          cur_state, new_state, status);
                err = -EINVAL;
        }
 
@@ -1078,10 +993,10 @@ static int mthca_map_memfree(struct mthca_dev *dev,
                if (ret)
                        goto err_qpc;
 
-               ret = mthca_table_get(dev, dev->qp_table.rdb_table,
-                                     qp->qpn << dev->qp_table.rdb_shift);
-               if (ret)
-                       goto err_eqpc;
+               ret = mthca_table_get(dev, dev->qp_table.rdb_table,
+                                     qp->qpn << dev->qp_table.rdb_shift);
+               if (ret)
+                       goto err_eqpc;
 
        }
 
@@ -1393,7 +1308,8 @@ void mthca_free_qp(struct mthca_dev *dev,
        wait_event(qp->wait, !atomic_read(&qp->refcount));
 
        if (qp->state != IB_QPS_RESET)
-               mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status);
+               mthca_MODIFY_QP(dev, qp->state, IB_QPS_RESET, qp->qpn, 0,
+                               NULL, 0, &status);
 
        /*
         * If this is a userspace QP, the buffers, MR, CQs and so on
@@ -1699,7 +1615,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                    mthca_opcode[wr->opcode]);
                wmb();
                ((struct mthca_next_seg *) prev_wqe)->ee_nds =
-                       cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size);
+                       cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size |
+                                   ((wr->send_flags & IB_SEND_FENCE) ?
+                                   MTHCA_NEXT_FENCE : 0));
 
                if (!size0) {
                        size0 = size;
@@ -2061,7 +1979,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                                    mthca_opcode[wr->opcode]);
                wmb();
                ((struct mthca_next_seg *) prev_wqe)->ee_nds =
-                       cpu_to_be32(MTHCA_NEXT_DBD | size);
+                       cpu_to_be32(MTHCA_NEXT_DBD | size |
+                                    ((wr->send_flags & IB_SEND_FENCE) ?
+                                    MTHCA_NEXT_FENCE : 0));
 
                if (!size0) {
                        size0 = size;
@@ -2115,7 +2035,7 @@ int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
        int i;
        void *wqe;
 
-       spin_lock_irqsave(&qp->rq.lock, flags);
+       spin_lock_irqsave(&qp->rq.lock, flags);
 
        /* XXX check that state is OK to post receive */
 
@@ -2182,8 +2102,8 @@ out:
        return err;
 }
 
-int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
-                      int index, int *dbd, __be32 *new_wqe)
+void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
+                       int index, int *dbd, __be32 *new_wqe)
 {
        struct mthca_next_seg *next;
 
@@ -2193,7 +2113,7 @@ int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
         */
        if (qp->ibqp.srq) {
                *new_wqe = 0;
-               return 0;
+               return;
        }
 
        if (is_send)
@@ -2207,8 +2127,6 @@ int mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send,
                        (next->ee_nds & cpu_to_be32(0x3f));
        else
                *new_wqe = 0;
-
-       return 0;
 }
 
 int __devinit mthca_init_qp_table(struct mthca_dev *dev)
index e7e153d..47a6a75 100644 (file)
@@ -49,7 +49,8 @@ struct mthca_tavor_srq_context {
        __be32 state_pd;
        __be32 lkey;
        __be32 uar;
-       __be32 wqe_cnt;
+       __be16 limit_watermark;
+       __be16 wqe_cnt;
        u32    reserved[2];
 };
 
@@ -271,6 +272,9 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
        srq->first_free = 0;
        srq->last_free  = srq->max - 1;
 
+       attr->max_wr    = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
+       attr->max_sge   = srq->max_gs;
+
        return 0;
 
 err_out_free_srq:
@@ -339,7 +343,7 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
 
 int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
                     enum ib_srq_attr_mask attr_mask)
-{      
+{
        struct mthca_dev *dev = to_mdev(ibsrq->device);
        struct mthca_srq *srq = to_msrq(ibsrq);
        int ret;
@@ -360,6 +364,41 @@ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
        return 0;
 }
 
+int mthca_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+       struct mthca_dev *dev = to_mdev(ibsrq->device);
+       struct mthca_srq *srq = to_msrq(ibsrq);
+       struct mthca_mailbox *mailbox;
+       struct mthca_arbel_srq_context *arbel_ctx;
+       struct mthca_tavor_srq_context *tavor_ctx;
+       u8 status;
+       int err;
+
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       err = mthca_QUERY_SRQ(dev, srq->srqn, mailbox, &status);
+       if (err)
+               goto out;
+
+       if (mthca_is_memfree(dev)) {
+               arbel_ctx = mailbox->buf;
+               srq_attr->srq_limit = be16_to_cpu(arbel_ctx->limit_watermark);
+       } else {
+               tavor_ctx = mailbox->buf;
+               srq_attr->srq_limit = be16_to_cpu(tavor_ctx->limit_watermark);
+       }
+
+       srq_attr->max_wr  = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
+       srq_attr->max_sge = srq->max_gs;
+
+out:
+       mthca_free_mailbox(dev, mailbox);
+
+       return err;
+}
+
 void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
                     enum ib_event_type event_type)
 {
index bb015c6..02cc0a7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -75,6 +75,11 @@ struct mthca_create_cq_resp {
        __u32 reserved;
 };
 
+struct mthca_resize_cq {
+       __u32 lkey;
+       __u32 reserved;
+};
+
 struct mthca_create_srq {
        __u32 lkey;
        __u32 db_index;
index 2f85a9a..1251f86 100644 (file)
@@ -217,10 +217,16 @@ struct ipoib_neigh {
        struct list_head    list;
 };
 
+/*
+ * We stash a pointer to our private neighbour information after our
+ * hardware address in neigh->ha.  The ALIGN() expression here makes
+ * sure that this pointer is stored aligned so that an unaligned
+ * load is not needed to dereference it.
+ */
 static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh)
 {
-       return (struct ipoib_neigh **) (neigh->ha + 24 -
-                                       (offsetof(struct neighbour, ha) & 4));
+       return (void*) neigh + ALIGN(offsetof(struct neighbour, ha) +
+                                    INFINIBAND_ALEN, sizeof(void *));
 }
 
 extern struct workqueue_struct *ipoib_workqueue;
@@ -253,7 +259,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev);
 
 int ipoib_ib_dev_open(struct net_device *dev);
 int ipoib_ib_dev_up(struct net_device *dev);
-int ipoib_ib_dev_down(struct net_device *dev);
+int ipoib_ib_dev_down(struct net_device *dev, int flush);
 int ipoib_ib_dev_stop(struct net_device *dev);
 
 int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
index 86bcdd7..a1f5a05 100644 (file)
@@ -416,6 +416,7 @@ int ipoib_ib_dev_open(struct net_device *dev)
        ret = ipoib_ib_post_receives(dev);
        if (ret) {
                ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
+               ipoib_ib_dev_stop(dev);
                return -1;
        }
 
@@ -434,7 +435,7 @@ int ipoib_ib_dev_up(struct net_device *dev)
        return ipoib_mcast_start_thread(dev);
 }
 
-int ipoib_ib_dev_down(struct net_device *dev)
+int ipoib_ib_dev_down(struct net_device *dev, int flush)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
@@ -449,10 +450,11 @@ int ipoib_ib_dev_down(struct net_device *dev)
                set_bit(IPOIB_PKEY_STOP, &priv->flags);
                cancel_delayed_work(&priv->pkey_task);
                mutex_unlock(&pkey_mutex);
-               flush_workqueue(ipoib_workqueue);
+               if (flush)
+                       flush_workqueue(ipoib_workqueue);
        }
 
-       ipoib_mcast_stop_thread(dev, 1);
+       ipoib_mcast_stop_thread(dev, flush);
        ipoib_mcast_dev_flush(dev);
 
        ipoib_flush_paths(dev);
@@ -590,7 +592,7 @@ void ipoib_ib_dev_flush(void *_dev)
 
        ipoib_dbg(priv, "flushing\n");
 
-       ipoib_ib_dev_down(dev);
+       ipoib_ib_dev_down(dev, 0);
 
        /*
         * The device could have been brought down between the start and when
index c3b5f79..37da8d3 100644 (file)
@@ -133,7 +133,13 @@ static int ipoib_stop(struct net_device *dev)
 
        netif_stop_queue(dev);
 
-       ipoib_ib_dev_down(dev);
+       /*
+        * Now flush workqueue to make sure a scheduled task doesn't
+        * bring our internal state back up.
+        */
+       flush_workqueue(ipoib_workqueue);
+
+       ipoib_ib_dev_down(dev, 1);
        ipoib_ib_dev_stop(dev);
 
        if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
@@ -247,7 +253,6 @@ static void path_free(struct net_device *dev, struct ipoib_path *path)
                if (neigh->ah)
                        ipoib_put_ah(neigh->ah);
                *to_ipoib_neigh(neigh->neighbour) = NULL;
-               neigh->neighbour->ops->destructor = NULL;
                kfree(neigh);
        }
 
@@ -513,12 +518,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
                           be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
        } else {
                neigh->ah  = NULL;
-               if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
-                       __skb_queue_tail(&neigh->queue, skb);
-               } else {
-                       ++priv->stats.tx_dropped;
-                       dev_kfree_skb_any(skb);
-               }
+               __skb_queue_tail(&neigh->queue, skb);
 
                if (!path->query && path_rec_start(dev, path))
                        goto err;
@@ -530,7 +530,6 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
 err:
        *to_ipoib_neigh(skb->dst->neighbour) = NULL;
        list_del(&neigh->list);
-       neigh->neighbour->ops->destructor = NULL;
        kfree(neigh);
 
        ++priv->stats.tx_dropped;
@@ -769,21 +768,9 @@ static void ipoib_neigh_destructor(struct neighbour *n)
                ipoib_put_ah(ah);
 }
 
-static int ipoib_neigh_setup(struct neighbour *neigh)
-{
-       /*
-        * Is this kosher?  I can't find anybody in the kernel that
-        * sets neigh->destructor, so we should be able to set it here
-        * without trouble.
-        */
-       neigh->ops->destructor = ipoib_neigh_destructor;
-
-       return 0;
-}
-
 static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms)
 {
-       parms->neigh_setup = ipoib_neigh_setup;
+       parms->neigh_destructor = ipoib_neigh_destructor;
 
        return 0;
 }
index a2408d7..93c462e 100644 (file)
@@ -115,7 +115,6 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
                if (neigh->ah)
                        ipoib_put_ah(neigh->ah);
                *to_ipoib_neigh(neigh->neighbour) = NULL;
-               neigh->neighbour->ops->destructor = NULL;
                kfree(neigh);
        }
 
@@ -213,6 +212,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
 {
        struct net_device *dev = mcast->dev;
        struct ipoib_dev_priv *priv = netdev_priv(dev);
+       struct ipoib_ah *ah;
        int ret;
 
        mcast->mcmember = *mcmember;
@@ -269,8 +269,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
                                av.static_rate, priv->local_rate,
                                ib_sa_rate_enum_to_int(mcast->mcmember.rate));
 
-               mcast->ah = ipoib_create_ah(dev, priv->pd, &av);
-               if (!mcast->ah) {
+               ah = ipoib_create_ah(dev, priv->pd, &av);
+               if (!ah) {
                        ipoib_warn(priv, "ib_address_create failed\n");
                } else {
                        ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT
@@ -280,6 +280,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
                                        be16_to_cpu(mcast->mcmember.mlid),
                                        mcast->mcmember.sl);
                }
+
+               spin_lock_irq(&priv->lock);
+               mcast->ah = ah;
+               spin_unlock_irq(&priv->lock);
        }
 
        /* actually send any queued packets */
@@ -432,9 +436,11 @@ static void ipoib_mcast_join_complete(int status,
        if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
                mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
 
+       mutex_lock(&mcast_mutex);
+
+       spin_lock_irq(&priv->lock);
        mcast->query = NULL;
 
-       mutex_lock(&mcast_mutex);
        if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
                if (status == -ETIMEDOUT)
                        queue_work(ipoib_workqueue, &priv->mcast_task);
@@ -443,6 +449,7 @@ static void ipoib_mcast_join_complete(int status,
                                           mcast->backoff * HZ);
        } else
                complete(&mcast->done);
+       spin_unlock_irq(&priv->lock);
        mutex_unlock(&mcast_mutex);
 
        return;
@@ -630,21 +637,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
        if (flush)
                flush_workqueue(ipoib_workqueue);
 
+       spin_lock_irq(&priv->lock);
        if (priv->broadcast && priv->broadcast->query) {
                ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query);
                priv->broadcast->query = NULL;
+               spin_unlock_irq(&priv->lock);
                ipoib_dbg_mcast(priv, "waiting for bcast\n");
                wait_for_completion(&priv->broadcast->done);
-       }
+       } else
+               spin_unlock_irq(&priv->lock);
 
        list_for_each_entry(mcast, &priv->multicast_list, list) {
+               spin_lock_irq(&priv->lock);
                if (mcast->query) {
                        ib_sa_cancel_query(mcast->query_id, mcast->query);
                        mcast->query = NULL;
+                       spin_unlock_irq(&priv->lock);
                        ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
                                        IPOIB_GID_ARG(mcast->mcmember.mgid));
                        wait_for_completion(&mcast->done);
-               }
+               } else
+                       spin_unlock_irq(&priv->lock);
        }
 
        return 0;
index faaf10e..18d2f53 100644 (file)
@@ -255,6 +255,6 @@ void ipoib_event(struct ib_event_handler *handler,
            record->event == IB_EVENT_LID_CHANGE  ||
            record->event == IB_EVENT_SM_CHANGE) {
                ipoib_dbg(priv, "Port active event\n");
-               schedule_work(&priv->flush_task);
+               queue_work(ipoib_workqueue, &priv->flush_task);
        }
 }
index 960dae5..a13dcdf 100644 (file)
@@ -1237,6 +1237,87 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
        return ret;
 }
 
+static ssize_t show_id_ext(struct class_device *cdev, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+       if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_REMOVED)
+               return -ENODEV;
+
+       return sprintf(buf, "0x%016llx\n",
+                      (unsigned long long) be64_to_cpu(target->id_ext));
+}
+
+static ssize_t show_ioc_guid(struct class_device *cdev, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+       if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_REMOVED)
+               return -ENODEV;
+
+       return sprintf(buf, "0x%016llx\n",
+                      (unsigned long long) be64_to_cpu(target->ioc_guid));
+}
+
+static ssize_t show_service_id(struct class_device *cdev, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+       if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_REMOVED)
+               return -ENODEV;
+
+       return sprintf(buf, "0x%016llx\n",
+                      (unsigned long long) be64_to_cpu(target->service_id));
+}
+
+static ssize_t show_pkey(struct class_device *cdev, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+       if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_REMOVED)
+               return -ENODEV;
+
+       return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey));
+}
+
+static ssize_t show_dgid(struct class_device *cdev, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+       if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_REMOVED)
+               return -ENODEV;
+
+       return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                      be16_to_cpu(((__be16 *) target->path.dgid.raw)[0]),
+                      be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]),
+                      be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]),
+                      be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]),
+                      be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]),
+                      be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]),
+                      be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]),
+                      be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
+}
+
+static CLASS_DEVICE_ATTR(id_ext,       S_IRUGO, show_id_ext,           NULL);
+static CLASS_DEVICE_ATTR(ioc_guid,     S_IRUGO, show_ioc_guid,         NULL);
+static CLASS_DEVICE_ATTR(service_id,   S_IRUGO, show_service_id,       NULL);
+static CLASS_DEVICE_ATTR(pkey,         S_IRUGO, show_pkey,             NULL);
+static CLASS_DEVICE_ATTR(dgid,         S_IRUGO, show_dgid,             NULL);
+
+static struct class_device_attribute *srp_host_attrs[] = {
+       &class_device_attr_id_ext,
+       &class_device_attr_ioc_guid,
+       &class_device_attr_service_id,
+       &class_device_attr_pkey,
+       &class_device_attr_dgid,
+       NULL
+};
+
 static struct scsi_host_template srp_template = {
        .module                         = THIS_MODULE,
        .name                           = DRV_NAME,
@@ -1249,7 +1330,8 @@ static struct scsi_host_template srp_template = {
        .this_id                        = -1,
        .sg_tablesize                   = SRP_MAX_INDIRECT,
        .cmd_per_lun                    = SRP_SQ_SIZE,
-       .use_clustering                 = ENABLE_CLUSTERING
+       .use_clustering                 = ENABLE_CLUSTERING,
+       .shost_attrs                    = srp_host_attrs
 };
 
 static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
@@ -1366,6 +1448,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
                                strlcpy(dgid, p + i * 2, 3);
                                target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
                        }
+                       kfree(p);
                        break;
 
                case SRP_OPT_PKEY:
index bd458cb..61b8961 100644 (file)
@@ -1,5 +1,6 @@
 saa7146-objs    := saa7146_i2c.o saa7146_core.o
 saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+ir-common-objs  := ir-functions.o ir-keymaps.o
 
 obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
 obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
deleted file mode 100644 (file)
index 97fa3fc..0000000
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- *
- * some common structs and functions to handle infrared remotes via
- * input layer ...
- *
- * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/string.h>
-#include <media/ir-common.h>
-
-/* -------------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-static int repeat = 1;
-module_param(repeat, int, 0444);
-MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
-
-static int debug = 0;    /* debug level (0,1,2) */
-module_param(debug, int, 0644);
-
-#define dprintk(level, fmt, arg...)    if (debug >= level) \
-       printk(KERN_DEBUG fmt , ## arg)
-
-/* -------------------------------------------------------------------------- */
-
-/* generic RC5 keytable                                          */
-/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
-/* used by old (black) Hauppauge remotes                         */
-IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
-       /* Keys 0 to 9 */
-       [ 0x00 ] = KEY_KP0,
-       [ 0x01 ] = KEY_KP1,
-       [ 0x02 ] = KEY_KP2,
-       [ 0x03 ] = KEY_KP3,
-       [ 0x04 ] = KEY_KP4,
-       [ 0x05 ] = KEY_KP5,
-       [ 0x06 ] = KEY_KP6,
-       [ 0x07 ] = KEY_KP7,
-       [ 0x08 ] = KEY_KP8,
-       [ 0x09 ] = KEY_KP9,
-
-       [ 0x0b ] = KEY_CHANNEL,         /* channel / program (japan: 11) */
-       [ 0x0c ] = KEY_POWER,           /* standby */
-       [ 0x0d ] = KEY_MUTE,            /* mute / demute */
-       [ 0x0f ] = KEY_TV,              /* display */
-       [ 0x10 ] = KEY_VOLUMEUP,
-       [ 0x11 ] = KEY_VOLUMEDOWN,
-       [ 0x12 ] = KEY_BRIGHTNESSUP,
-       [ 0x13 ] = KEY_BRIGHTNESSDOWN,
-       [ 0x1e ] = KEY_SEARCH,          /* search + */
-       [ 0x20 ] = KEY_CHANNELUP,       /* channel / program + */
-       [ 0x21 ] = KEY_CHANNELDOWN,     /* channel / program - */
-       [ 0x22 ] = KEY_CHANNEL,         /* alt / channel */
-       [ 0x23 ] = KEY_LANGUAGE,        /* 1st / 2nd language */
-       [ 0x26 ] = KEY_SLEEP,           /* sleeptimer */
-       [ 0x2e ] = KEY_MENU,            /* 2nd controls (USA: menu) */
-       [ 0x30 ] = KEY_PAUSE,
-       [ 0x32 ] = KEY_REWIND,
-       [ 0x33 ] = KEY_GOTO,
-       [ 0x35 ] = KEY_PLAY,
-       [ 0x36 ] = KEY_STOP,
-       [ 0x37 ] = KEY_RECORD,          /* recording */
-       [ 0x3c ] = KEY_TEXT,            /* teletext submode (Japan: 12) */
-       [ 0x3d ] = KEY_SUSPEND,         /* system standby */
-
-};
-EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
-
-/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
-IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
-       /* Keys 0 to 9 */
-       [ 18 ] = KEY_KP0,
-       [  5 ] = KEY_KP1,
-       [  6 ] = KEY_KP2,
-       [  7 ] = KEY_KP3,
-       [  9 ] = KEY_KP4,
-       [ 10 ] = KEY_KP5,
-       [ 11 ] = KEY_KP6,
-       [ 13 ] = KEY_KP7,
-       [ 14 ] = KEY_KP8,
-       [ 15 ] = KEY_KP9,
-
-       [  0 ] = KEY_POWER,
-       [  2 ] = KEY_TUNER,             /* TV/FM */
-       [ 30 ] = KEY_VIDEO,
-       [  4 ] = KEY_VOLUMEUP,
-       [  8 ] = KEY_VOLUMEDOWN,
-       [ 12 ] = KEY_CHANNELUP,
-       [ 16 ] = KEY_CHANNELDOWN,
-       [  3 ] = KEY_ZOOM,              /* fullscreen */
-       [ 31 ] = KEY_SUBTITLE,          /* closed caption/teletext */
-       [ 32 ] = KEY_SLEEP,
-       [ 20 ] = KEY_MUTE,
-       [ 43 ] = KEY_RED,
-       [ 44 ] = KEY_GREEN,
-       [ 45 ] = KEY_YELLOW,
-       [ 46 ] = KEY_BLUE,
-       [ 24 ] = KEY_KPPLUS,            /* fine tune + */
-       [ 25 ] = KEY_KPMINUS,           /* fine tune - */
-       [ 33 ] = KEY_KPDOT,
-       [ 19 ] = KEY_KPENTER,
-       [ 34 ] = KEY_BACK,
-       [ 35 ] = KEY_PLAYPAUSE,
-       [ 36 ] = KEY_NEXT,
-       [ 38 ] = KEY_STOP,
-       [ 39 ] = KEY_RECORD
-};
-EXPORT_SYMBOL_GPL(ir_codes_winfast);
-
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
-       [ 0x59 ] = KEY_MUTE,
-       [ 0x4a ] = KEY_POWER,
-
-       [ 0x18 ] = KEY_TEXT,
-       [ 0x26 ] = KEY_TV,
-       [ 0x3d ] = KEY_PRINT,
-
-       [ 0x48 ] = KEY_RED,
-       [ 0x04 ] = KEY_GREEN,
-       [ 0x11 ] = KEY_YELLOW,
-       [ 0x00 ] = KEY_BLUE,
-
-       [ 0x2d ] = KEY_VOLUMEUP,
-       [ 0x1e ] = KEY_VOLUMEDOWN,
-
-       [ 0x49 ] = KEY_MENU,
-
-       [ 0x16 ] = KEY_CHANNELUP,
-       [ 0x17 ] = KEY_CHANNELDOWN,
-
-       [ 0x20 ] = KEY_UP,
-       [ 0x21 ] = KEY_DOWN,
-       [ 0x22 ] = KEY_LEFT,
-       [ 0x23 ] = KEY_RIGHT,
-       [ 0x0d ] = KEY_SELECT,
-
-
-
-       [ 0x08 ] = KEY_BACK,
-       [ 0x07 ] = KEY_REFRESH,
-
-       [ 0x2f ] = KEY_ZOOM,
-       [ 0x29 ] = KEY_RECORD,
-
-       [ 0x4b ] = KEY_PAUSE,
-       [ 0x4d ] = KEY_REWIND,
-       [ 0x2e ] = KEY_PLAY,
-       [ 0x4e ] = KEY_FORWARD,
-       [ 0x53 ] = KEY_PREVIOUS,
-       [ 0x4c ] = KEY_STOP,
-       [ 0x54 ] = KEY_NEXT,
-
-       [ 0x69 ] = KEY_KP0,
-       [ 0x6a ] = KEY_KP1,
-       [ 0x6b ] = KEY_KP2,
-       [ 0x6c ] = KEY_KP3,
-       [ 0x6d ] = KEY_KP4,
-       [ 0x6e ] = KEY_KP5,
-       [ 0x6f ] = KEY_KP6,
-       [ 0x70 ] = KEY_KP7,
-       [ 0x71 ] = KEY_KP8,
-       [ 0x72 ] = KEY_KP9,
-
-       [ 0x74 ] = KEY_CHANNEL,
-       [ 0x0a ] = KEY_BACKSPACE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
-
-/* empty keytable, can be used as placeholder for not-yet created keytables */
-IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
-       [ 42 ] = KEY_COFFEE,
-};
-EXPORT_SYMBOL_GPL(ir_codes_empty);
-
-/* Hauppauge: the newer, gray remotes (seems there are multiple
- * slightly different versions), shipped with cx88+ivtv cards.
- * almost rc5 coding, but some non-standard keys */
-IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
-       /* Keys 0 to 9 */
-       [ 0x00 ] = KEY_KP0,
-       [ 0x01 ] = KEY_KP1,
-       [ 0x02 ] = KEY_KP2,
-       [ 0x03 ] = KEY_KP3,
-       [ 0x04 ] = KEY_KP4,
-       [ 0x05 ] = KEY_KP5,
-       [ 0x06 ] = KEY_KP6,
-       [ 0x07 ] = KEY_KP7,
-       [ 0x08 ] = KEY_KP8,
-       [ 0x09 ] = KEY_KP9,
-
-       [ 0x0a ] = KEY_TEXT,            /* keypad asterisk as well */
-       [ 0x0b ] = KEY_RED,             /* red button */
-       [ 0x0c ] = KEY_RADIO,
-       [ 0x0d ] = KEY_MENU,
-       [ 0x0e ] = KEY_SUBTITLE,        /* also the # key */
-       [ 0x0f ] = KEY_MUTE,
-       [ 0x10 ] = KEY_VOLUMEUP,
-       [ 0x11 ] = KEY_VOLUMEDOWN,
-       [ 0x12 ] = KEY_PREVIOUS,        /* previous channel */
-       [ 0x14 ] = KEY_UP,
-       [ 0x15 ] = KEY_DOWN,
-       [ 0x16 ] = KEY_LEFT,
-       [ 0x17 ] = KEY_RIGHT,
-       [ 0x18 ] = KEY_VIDEO,           /* Videos */
-       [ 0x19 ] = KEY_AUDIO,           /* Music */
-       /* 0x1a: Pictures - presume this means
-          "Multimedia Home Platform" -
-          no "PICTURES" key in input.h
-        */
-       [ 0x1a ] = KEY_MHP,
-
-       [ 0x1b ] = KEY_EPG,             /* Guide */
-       [ 0x1c ] = KEY_TV,
-       [ 0x1e ] = KEY_NEXTSONG,        /* skip >| */
-       [ 0x1f ] = KEY_EXIT,            /* back/exit */
-       [ 0x20 ] = KEY_CHANNELUP,       /* channel / program + */
-       [ 0x21 ] = KEY_CHANNELDOWN,     /* channel / program - */
-       [ 0x22 ] = KEY_CHANNEL,         /* source (old black remote) */
-       [ 0x24 ] = KEY_PREVIOUSSONG,    /* replay |< */
-       [ 0x25 ] = KEY_ENTER,           /* OK */
-       [ 0x26 ] = KEY_SLEEP,           /* minimize (old black remote) */
-       [ 0x29 ] = KEY_BLUE,            /* blue key */
-       [ 0x2e ] = KEY_GREEN,           /* green button */
-       [ 0x30 ] = KEY_PAUSE,           /* pause */
-       [ 0x32 ] = KEY_REWIND,          /* backward << */
-       [ 0x34 ] = KEY_FASTFORWARD,     /* forward >> */
-       [ 0x35 ] = KEY_PLAY,
-       [ 0x36 ] = KEY_STOP,
-       [ 0x37 ] = KEY_RECORD,          /* recording */
-       [ 0x38 ] = KEY_YELLOW,          /* yellow key */
-       [ 0x3b ] = KEY_SELECT,          /* top right button */
-       [ 0x3c ] = KEY_ZOOM,            /* full */
-       [ 0x3d ] = KEY_POWER,           /* system power (green button) */
-};
-EXPORT_SYMBOL(ir_codes_hauppauge_new);
-
-IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
-       [  2 ] = KEY_KP0,
-       [  1 ] = KEY_KP1,
-       [ 11 ] = KEY_KP2,
-       [ 27 ] = KEY_KP3,
-       [  5 ] = KEY_KP4,
-       [  9 ] = KEY_KP5,
-       [ 21 ] = KEY_KP6,
-       [  6 ] = KEY_KP7,
-       [ 10 ] = KEY_KP8,
-       [ 18 ] = KEY_KP9,
-
-       [  3 ] = KEY_TUNER,             /* TV/FM */
-       [  7 ] = KEY_SEARCH,            /* scan */
-       [ 28 ] = KEY_ZOOM,              /* full screen */
-       [ 30 ] = KEY_POWER,
-       [ 23 ] = KEY_VOLUMEDOWN,
-       [ 31 ] = KEY_VOLUMEUP,
-       [ 20 ] = KEY_CHANNELDOWN,
-       [ 22 ] = KEY_CHANNELUP,
-       [ 24 ] = KEY_MUTE,
-
-       [  0 ] = KEY_LIST,              /* source */
-       [ 19 ] = KEY_INFO,              /* loop */
-       [ 16 ] = KEY_LAST,              /* +100 */
-       [ 13 ] = KEY_CLEAR,             /* reset */
-       [ 12 ] = BTN_RIGHT,             /* fun++ */
-       [  4 ] = BTN_LEFT,              /* fun-- */
-       [ 14 ] = KEY_GOTO,              /* function */
-       [ 15 ] = KEY_STOP,              /* freeze */
-};
-EXPORT_SYMBOL(ir_codes_pixelview);
-
-/* -------------------------------------------------------------------------- */
-
-static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
-{
-       if (KEY_RESERVED == ir->keycode) {
-               printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
-                      dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
-               return;
-       }
-       dprintk(1,"%s: key event code=%d down=%d\n",
-               dev->name,ir->keycode,ir->keypressed);
-       input_report_key(dev,ir->keycode,ir->keypressed);
-       input_sync(dev);
-}
-
-/* -------------------------------------------------------------------------- */
-
-void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
-                  int ir_type, IR_KEYTAB_TYPE *ir_codes)
-{
-       int i;
-
-       ir->ir_type = ir_type;
-       if (ir_codes)
-               memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
-
-
-       dev->keycode     = ir->ir_codes;
-       dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
-       dev->keycodemax  = IR_KEYTAB_SIZE;
-       for (i = 0; i < IR_KEYTAB_SIZE; i++)
-               set_bit(ir->ir_codes[i], dev->keybit);
-       clear_bit(0, dev->keybit);
-
-       set_bit(EV_KEY, dev->evbit);
-       if (repeat)
-               set_bit(EV_REP, dev->evbit);
-}
-
-void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
-{
-       if (ir->keypressed) {
-               ir->keypressed = 0;
-               ir_input_key_event(dev,ir);
-       }
-}
-
-void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
-                     u32 ir_key, u32 ir_raw)
-{
-       u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
-
-       if (ir->keypressed && ir->keycode != keycode) {
-               ir->keypressed = 0;
-               ir_input_key_event(dev,ir);
-       }
-       if (!ir->keypressed) {
-               ir->ir_key  = ir_key;
-               ir->ir_raw  = ir_raw;
-               ir->keycode = keycode;
-               ir->keypressed = 1;
-               ir_input_key_event(dev,ir);
-       }
-}
-
-/* -------------------------------------------------------------------------- */
-
-u32 ir_extract_bits(u32 data, u32 mask)
-{
-       int mbit, vbit;
-       u32 value;
-
-       value = 0;
-       vbit  = 0;
-       for (mbit = 0; mbit < 32; mbit++) {
-               if (!(mask & ((u32)1 << mbit)))
-                       continue;
-               if (data & ((u32)1 << mbit))
-                       value |= (1 << vbit);
-               vbit++;
-       }
-       return value;
-}
-
-static int inline getbit(u32 *samples, int bit)
-{
-       return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
-}
-
-/* sump raw samples for visual debugging ;) */
-int ir_dump_samples(u32 *samples, int count)
-{
-       int i, bit, start;
-
-       printk(KERN_DEBUG "ir samples: ");
-       start = 0;
-       for (i = 0; i < count * 32; i++) {
-               bit = getbit(samples,i);
-               if (bit)
-                       start = 1;
-               if (0 == start)
-                       continue;
-               printk("%s", bit ? "#" : "_");
-       }
-       printk("\n");
-       return 0;
-}
-
-/* decode raw samples, pulse distance coding used by NEC remotes */
-int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
-{
-       int i,last,bit,len;
-       u32 curBit;
-       u32 value;
-
-       /* find start burst */
-       for (i = len = 0; i < count * 32; i++) {
-               bit = getbit(samples,i);
-               if (bit) {
-                       len++;
-               } else {
-                       if (len >= 29)
-                               break;
-                       len = 0;
-               }
-       }
-
-       /* start burst to short */
-       if (len < 29)
-               return 0xffffffff;
-
-       /* find start silence */
-       for (len = 0; i < count * 32; i++) {
-               bit = getbit(samples,i);
-               if (bit) {
-                       break;
-               } else {
-                       len++;
-               }
-       }
-
-       /* silence to short */
-       if (len < 7)
-               return 0xffffffff;
-
-       /* go decoding */
-       len   = 0;
-       last = 1;
-       value = 0; curBit = 1;
-       for (; i < count * 32; i++) {
-               bit  = getbit(samples,i);
-               if (last) {
-                       if(bit) {
-                               continue;
-                       } else {
-                               len = 1;
-                       }
-               } else {
-                       if (bit) {
-                               if (len > (low + high) /2)
-                                       value |= curBit;
-                               curBit <<= 1;
-                               if (curBit == 1)
-                                       break;
-                       } else {
-                               len++;
-                       }
-               }
-               last = bit;
-       }
-
-       return value;
-}
-
-/* decode raw samples, biphase coding, used by rc5 for example */
-int ir_decode_biphase(u32 *samples, int count, int low, int high)
-{
-       int i,last,bit,len,flips;
-       u32 value;
-
-       /* find start bit (1) */
-       for (i = 0; i < 32; i++) {
-               bit = getbit(samples,i);
-               if (bit)
-                       break;
-       }
-
-       /* go decoding */
-       len   = 0;
-       flips = 0;
-       value = 1;
-       for (; i < count * 32; i++) {
-               if (len > high)
-                       break;
-               if (flips > 1)
-                       break;
-               last = bit;
-               bit  = getbit(samples,i);
-               if (last == bit) {
-                       len++;
-                       continue;
-               }
-               if (len < low) {
-                       len++;
-                       flips++;
-                       continue;
-               }
-               value <<= 1;
-               value |= bit;
-               flips = 0;
-               len   = 1;
-       }
-       return value;
-}
-
-EXPORT_SYMBOL_GPL(ir_input_init);
-EXPORT_SYMBOL_GPL(ir_input_nokey);
-EXPORT_SYMBOL_GPL(ir_input_keydown);
-
-EXPORT_SYMBOL_GPL(ir_extract_bits);
-EXPORT_SYMBOL_GPL(ir_dump_samples);
-EXPORT_SYMBOL_GPL(ir_decode_biphase);
-EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
new file mode 100644 (file)
index 0000000..397cff8
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ *
+ * some common structs and functions to handle infrared remotes via
+ * input layer ...
+ *
+ * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <media/ir-common.h>
+
+/* -------------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static int repeat = 1;
+module_param(repeat, int, 0444);
+MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
+
+static int debug = 0;    /* debug level (0,1,2) */
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...)    if (debug >= level) \
+       printk(KERN_DEBUG fmt , ## arg)
+
+/* -------------------------------------------------------------------------- */
+
+static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
+{
+       if (KEY_RESERVED == ir->keycode) {
+               printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
+                      dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
+               return;
+       }
+       dprintk(1,"%s: key event code=%d down=%d\n",
+               dev->name,ir->keycode,ir->keypressed);
+       input_report_key(dev,ir->keycode,ir->keypressed);
+       input_sync(dev);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
+                  int ir_type, IR_KEYTAB_TYPE *ir_codes)
+{
+       int i;
+
+       ir->ir_type = ir_type;
+       if (ir_codes)
+               memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
+
+
+       dev->keycode     = ir->ir_codes;
+       dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
+       dev->keycodemax  = IR_KEYTAB_SIZE;
+       for (i = 0; i < IR_KEYTAB_SIZE; i++)
+               set_bit(ir->ir_codes[i], dev->keybit);
+       clear_bit(0, dev->keybit);
+
+       set_bit(EV_KEY, dev->evbit);
+       if (repeat)
+               set_bit(EV_REP, dev->evbit);
+}
+
+void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
+{
+       if (ir->keypressed) {
+               ir->keypressed = 0;
+               ir_input_key_event(dev,ir);
+       }
+}
+
+void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
+                     u32 ir_key, u32 ir_raw)
+{
+       u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
+
+       if (ir->keypressed && ir->keycode != keycode) {
+               ir->keypressed = 0;
+               ir_input_key_event(dev,ir);
+       }
+       if (!ir->keypressed) {
+               ir->ir_key  = ir_key;
+               ir->ir_raw  = ir_raw;
+               ir->keycode = keycode;
+               ir->keypressed = 1;
+               ir_input_key_event(dev,ir);
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+u32 ir_extract_bits(u32 data, u32 mask)
+{
+       int mbit, vbit;
+       u32 value;
+
+       value = 0;
+       vbit  = 0;
+       for (mbit = 0; mbit < 32; mbit++) {
+               if (!(mask & ((u32)1 << mbit)))
+                       continue;
+               if (data & ((u32)1 << mbit))
+                       value |= (1 << vbit);
+               vbit++;
+       }
+       return value;
+}
+
+static int inline getbit(u32 *samples, int bit)
+{
+       return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
+}
+
+/* sump raw samples for visual debugging ;) */
+int ir_dump_samples(u32 *samples, int count)
+{
+       int i, bit, start;
+
+       printk(KERN_DEBUG "ir samples: ");
+       start = 0;
+       for (i = 0; i < count * 32; i++) {
+               bit = getbit(samples,i);
+               if (bit)
+                       start = 1;
+               if (0 == start)
+                       continue;
+               printk("%s", bit ? "#" : "_");
+       }
+       printk("\n");
+       return 0;
+}
+
+/* decode raw samples, pulse distance coding used by NEC remotes */
+int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
+{
+       int i,last,bit,len;
+       u32 curBit;
+       u32 value;
+
+       /* find start burst */
+       for (i = len = 0; i < count * 32; i++) {
+               bit = getbit(samples,i);
+               if (bit) {
+                       len++;
+               } else {
+                       if (len >= 29)
+                               break;
+                       len = 0;
+               }
+       }
+
+       /* start burst to short */
+       if (len < 29)
+               return 0xffffffff;
+
+       /* find start silence */
+       for (len = 0; i < count * 32; i++) {
+               bit = getbit(samples,i);
+               if (bit) {
+                       break;
+               } else {
+                       len++;
+               }
+       }
+
+       /* silence to short */
+       if (len < 7)
+               return 0xffffffff;
+
+       /* go decoding */
+       len   = 0;
+       last = 1;
+       value = 0; curBit = 1;
+       for (; i < count * 32; i++) {
+               bit  = getbit(samples,i);
+               if (last) {
+                       if(bit) {
+                               continue;
+                       } else {
+                               len = 1;
+                       }
+               } else {
+                       if (bit) {
+                               if (len > (low + high) /2)
+                                       value |= curBit;
+                               curBit <<= 1;
+                               if (curBit == 1)
+                                       break;
+                       } else {
+                               len++;
+                       }
+               }
+               last = bit;
+       }
+
+       return value;
+}
+
+/* decode raw samples, biphase coding, used by rc5 for example */
+int ir_decode_biphase(u32 *samples, int count, int low, int high)
+{
+       int i,last,bit,len,flips;
+       u32 value;
+
+       /* find start bit (1) */
+       for (i = 0; i < 32; i++) {
+               bit = getbit(samples,i);
+               if (bit)
+                       break;
+       }
+
+       /* go decoding */
+       len   = 0;
+       flips = 0;
+       value = 1;
+       for (; i < count * 32; i++) {
+               if (len > high)
+                       break;
+               if (flips > 1)
+                       break;
+               last = bit;
+               bit  = getbit(samples,i);
+               if (last == bit) {
+                       len++;
+                       continue;
+               }
+               if (len < low) {
+                       len++;
+                       flips++;
+                       continue;
+               }
+               value <<= 1;
+               value |= bit;
+               flips = 0;
+               len   = 1;
+       }
+       return value;
+}
+
+EXPORT_SYMBOL_GPL(ir_input_init);
+EXPORT_SYMBOL_GPL(ir_input_nokey);
+EXPORT_SYMBOL_GPL(ir_input_keydown);
+
+EXPORT_SYMBOL_GPL(ir_extract_bits);
+EXPORT_SYMBOL_GPL(ir_dump_samples);
+EXPORT_SYMBOL_GPL(ir_decode_biphase);
+EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
new file mode 100644 (file)
index 0000000..a294d5c
--- /dev/null
@@ -0,0 +1,1415 @@
+/*
+
+
+    Keytables for supported remote controls. This file is part of
+    video4linux.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/input.h>
+#include <media/ir-common.h>
+
+/* empty keytable, can be used as placeholder for not-yet created keytables */
+IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
+       [ 0x2a ] = KEY_COFFEE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_empty);
+
+/* Matt Jesson <dvb@jesson.eclipse.co.uk */
+IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
+       [ 0x28 ] = KEY_0,         //'0' / 'enter'
+       [ 0x22 ] = KEY_1,         //'1'
+       [ 0x12 ] = KEY_2,         //'2' / 'up arrow'
+       [ 0x32 ] = KEY_3,         //'3'
+       [ 0x24 ] = KEY_4,         //'4' / 'left arrow'
+       [ 0x14 ] = KEY_5,         //'5'
+       [ 0x34 ] = KEY_6,         //'6' / 'right arrow'
+       [ 0x26 ] = KEY_7,         //'7'
+       [ 0x16 ] = KEY_8,         //'8' / 'down arrow'
+       [ 0x36 ] = KEY_9,         //'9'
+
+       [ 0x20 ] = KEY_LIST,        // 'source'
+       [ 0x10 ] = KEY_TEXT,        // 'teletext'
+       [ 0x00 ] = KEY_POWER,       // 'power'
+       [ 0x04 ] = KEY_AUDIO,       // 'audio'
+       [ 0x06 ] = KEY_ZOOM,        // 'full screen'
+       [ 0x18 ] = KEY_VIDEO,       // 'display'
+       [ 0x38 ] = KEY_SEARCH,      // 'loop'
+       [ 0x08 ] = KEY_INFO,        // 'preview'
+       [ 0x2a ] = KEY_REWIND,      // 'backward <<'
+       [ 0x1a ] = KEY_FASTFORWARD, // 'forward >>'
+       [ 0x3a ] = KEY_RECORD,      // 'capture'
+       [ 0x0a ] = KEY_MUTE,        // 'mute'
+       [ 0x2c ] = KEY_RECORD,      // 'record'
+       [ 0x1c ] = KEY_PAUSE,       // 'pause'
+       [ 0x3c ] = KEY_STOP,        // 'stop'
+       [ 0x0c ] = KEY_PLAY,        // 'play'
+       [ 0x2e ] = KEY_RED,         // 'red'
+       [ 0x01 ] = KEY_BLUE,        // 'blue' / 'cancel'
+       [ 0x0e ] = KEY_YELLOW,      // 'yellow' / 'ok'
+       [ 0x21 ] = KEY_GREEN,       // 'green'
+       [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -'
+       [ 0x31 ] = KEY_CHANNELUP,   // 'channel +'
+       [ 0x1e ] = KEY_VOLUMEDOWN,  // 'volume -'
+       [ 0x3e ] = KEY_VOLUMEUP,    // 'volume +'
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
+
+/* Attila Kondoros <attila.kondoros@chello.hu> */
+IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
+
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+       [ 0x00 ] = KEY_0,
+       [ 0x17 ] = KEY_LAST,        // +100
+       [ 0x0a ] = KEY_LIST,        // recall
+
+
+       [ 0x1c ] = KEY_TUNER,       // TV/FM
+       [ 0x15 ] = KEY_SEARCH,      // scan
+       [ 0x12 ] = KEY_POWER,       // power
+       [ 0x1f ] = KEY_VOLUMEDOWN,  // vol up
+       [ 0x1b ] = KEY_VOLUMEUP,    // vol down
+       [ 0x1e ] = KEY_CHANNELDOWN, // chn up
+       [ 0x1a ] = KEY_CHANNELUP,   // chn down
+
+       [ 0x11 ] = KEY_VIDEO,       // video
+       [ 0x0f ] = KEY_ZOOM,        // full screen
+       [ 0x13 ] = KEY_MUTE,        // mute/unmute
+       [ 0x10 ] = KEY_TEXT,        // min
+
+       [ 0x0d ] = KEY_STOP,        // freeze
+       [ 0x0e ] = KEY_RECORD,      // record
+       [ 0x1d ] = KEY_PLAYPAUSE,   // stop
+       [ 0x19 ] = KEY_PLAY,        // play
+
+       [ 0x16 ] = KEY_GOTO,        // osd
+       [ 0x14 ] = KEY_REFRESH,     // default
+       [ 0x0c ] = KEY_KPPLUS,      // fine tune >>>>
+       [ 0x18 ] = KEY_KPMINUS      // fine tune <<<<
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_apac_viewcomp);
+
+/* ---------------------------------------------------------------------- */
+
+IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
+
+       [ 0x1e ] = KEY_POWER,       // power
+       [ 0x07 ] = KEY_MEDIA,       // source
+       [ 0x1c ] = KEY_SEARCH,      // scan
+
+/* FIXME: duplicate keycodes?
+ *
+ * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
+ * The GPIO values are
+ * 6397fb for both "Scan <" and "CH -",
+ * 639ffb for "Scan >" and "CH+",
+ * 6384fb for "Tune <" and "<<<",
+ * 638cfb for "Tune >" and ">>>", regardless of the mask.
+ *
+ *     [ 0x17 ] = KEY_BACK,        // fm scan <<
+ *     [ 0x1f ] = KEY_FORWARD,     // fm scan >>
+ *
+ *     [ 0x04 ] = KEY_LEFT,        // fm tuning <
+ *     [ 0x0c ] = KEY_RIGHT,       // fm tuning >
+ *
+ * For now, these four keys are disabled. Pressing them will generate
+ * the CH+/CH-/<<</>>> events
+ */
+
+       [ 0x03 ] = KEY_TUNER,       // TV/FM
+
+       [ 0x00 ] = KEY_RECORD,
+       [ 0x08 ] = KEY_STOP,
+       [ 0x11 ] = KEY_PLAY,
+
+       [ 0x1a ] = KEY_PLAYPAUSE,   // freeze
+       [ 0x19 ] = KEY_ZOOM,        // zoom
+       [ 0x0f ] = KEY_TEXT,        // min
+
+       [ 0x01 ] = KEY_1,
+       [ 0x0b ] = KEY_2,
+       [ 0x1b ] = KEY_3,
+       [ 0x05 ] = KEY_4,
+       [ 0x09 ] = KEY_5,
+       [ 0x15 ] = KEY_6,
+       [ 0x06 ] = KEY_7,
+       [ 0x0a ] = KEY_8,
+       [ 0x12 ] = KEY_9,
+       [ 0x02 ] = KEY_0,
+       [ 0x10 ] = KEY_LAST,        // +100
+       [ 0x13 ] = KEY_LIST,        // recall
+
+       [ 0x1f ] = KEY_CHANNELUP,   // chn down
+       [ 0x17 ] = KEY_CHANNELDOWN, // chn up
+       [ 0x16 ] = KEY_VOLUMEUP,    // vol down
+       [ 0x14 ] = KEY_VOLUMEDOWN,  // vol up
+
+       [ 0x04 ] = KEY_KPMINUS,     // <<<
+       [ 0x0e ] = KEY_SETUP,       // function
+       [ 0x0c ] = KEY_KPPLUS,      // >>>
+
+       [ 0x0d ] = KEY_GOTO,        // mts
+       [ 0x1d ] = KEY_REFRESH,     // reset
+       [ 0x18 ] = KEY_MUTE         // mute/unmute
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pixelview);
+
+IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
+       [ 0x00 ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+       [ 0x0a ] = KEY_TV,
+       [ 0x0b ] = KEY_AUX,
+       [ 0x0c ] = KEY_DVD,
+       [ 0x0d ] = KEY_POWER,
+       [ 0x0e ] = KEY_MHP,     /* labelled 'Picture' */
+       [ 0x0f ] = KEY_AUDIO,
+       [ 0x10 ] = KEY_INFO,
+       [ 0x11 ] = KEY_F13,     /* 16:9 */
+       [ 0x12 ] = KEY_F14,     /* 14:9 */
+       [ 0x13 ] = KEY_EPG,
+       [ 0x14 ] = KEY_EXIT,
+       [ 0x15 ] = KEY_MENU,
+       [ 0x16 ] = KEY_UP,
+       [ 0x17 ] = KEY_DOWN,
+       [ 0x18 ] = KEY_LEFT,
+       [ 0x19 ] = KEY_RIGHT,
+       [ 0x1a ] = KEY_ENTER,
+       [ 0x1b ] = KEY_CHANNELUP,
+       [ 0x1c ] = KEY_CHANNELDOWN,
+       [ 0x1d ] = KEY_VOLUMEUP,
+       [ 0x1e ] = KEY_VOLUMEDOWN,
+       [ 0x1f ] = KEY_RED,
+       [ 0x20 ] = KEY_GREEN,
+       [ 0x21 ] = KEY_YELLOW,
+       [ 0x22 ] = KEY_BLUE,
+       [ 0x23 ] = KEY_SUBTITLE,
+       [ 0x24 ] = KEY_F15,     /* AD */
+       [ 0x25 ] = KEY_TEXT,
+       [ 0x26 ] = KEY_MUTE,
+       [ 0x27 ] = KEY_REWIND,
+       [ 0x28 ] = KEY_STOP,
+       [ 0x29 ] = KEY_PLAY,
+       [ 0x2a ] = KEY_FASTFORWARD,
+       [ 0x2b ] = KEY_F16,     /* chapter */
+       [ 0x2c ] = KEY_PAUSE,
+       [ 0x2d ] = KEY_PLAY,
+       [ 0x2e ] = KEY_RECORD,
+       [ 0x2f ] = KEY_F17,     /* picture in picture */
+       [ 0x30 ] = KEY_KPPLUS,  /* zoom in */
+       [ 0x31 ] = KEY_KPMINUS, /* zoom out */
+       [ 0x32 ] = KEY_F18,     /* capture */
+       [ 0x33 ] = KEY_F19,     /* web */
+       [ 0x34 ] = KEY_EMAIL,
+       [ 0x35 ] = KEY_PHONE,
+       [ 0x36 ] = KEY_PC
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_nebula);
+
+/* DigitalNow DNTV Live DVB-T Remote */
+IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
+       [ 0x00 ] = KEY_ESC,             /* 'go up a level?' */
+       /* Keys 0 to 9 */
+       [ 0x0a ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       [ 0x0b ] = KEY_TUNER,           /* tv/fm */
+       [ 0x0c ] = KEY_SEARCH,          /* scan */
+       [ 0x0d ] = KEY_STOP,
+       [ 0x0e ] = KEY_PAUSE,
+       [ 0x0f ] = KEY_LIST,            /* source */
+
+       [ 0x10 ] = KEY_MUTE,
+       [ 0x11 ] = KEY_REWIND,          /* backward << */
+       [ 0x12 ] = KEY_POWER,
+       [ 0x13 ] = KEY_S,                       /* snap */
+       [ 0x14 ] = KEY_AUDIO,           /* stereo */
+       [ 0x15 ] = KEY_CLEAR,           /* reset */
+       [ 0x16 ] = KEY_PLAY,
+       [ 0x17 ] = KEY_ENTER,
+       [ 0x18 ] = KEY_ZOOM,            /* full screen */
+       [ 0x19 ] = KEY_FASTFORWARD,     /* forward >> */
+       [ 0x1a ] = KEY_CHANNELUP,
+       [ 0x1b ] = KEY_VOLUMEUP,
+       [ 0x1c ] = KEY_INFO,            /* preview */
+       [ 0x1d ] = KEY_RECORD,          /* record */
+       [ 0x1e ] = KEY_CHANNELDOWN,
+       [ 0x1f ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvb_t);
+
+/* ---------------------------------------------------------------------- */
+
+/* IO-DATA BCTV7E Remote */
+IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
+       [ 0x40 ] = KEY_TV,
+       [ 0x20 ] = KEY_RADIO,           /* FM */
+       [ 0x60 ] = KEY_EPG,
+       [ 0x00 ] = KEY_POWER,
+
+       /* Keys 0 to 9 */
+       [ 0x44 ] = KEY_0,               /* 10 */
+       [ 0x50 ] = KEY_1,
+       [ 0x30 ] = KEY_2,
+       [ 0x70 ] = KEY_3,
+       [ 0x48 ] = KEY_4,
+       [ 0x28 ] = KEY_5,
+       [ 0x68 ] = KEY_6,
+       [ 0x58 ] = KEY_7,
+       [ 0x38 ] = KEY_8,
+       [ 0x78 ] = KEY_9,
+
+       [ 0x10 ] = KEY_L,                       /* Live */
+       [ 0x08 ] = KEY_T,                       /* Time Shift */
+
+       [ 0x18 ] = KEY_PLAYPAUSE,               /* Play */
+
+       [ 0x24 ] = KEY_ENTER,           /* 11 */
+       [ 0x64 ] = KEY_ESC,             /* 12 */
+       [ 0x04 ] = KEY_M,                       /* Multi */
+
+       [ 0x54 ] = KEY_VIDEO,
+       [ 0x34 ] = KEY_CHANNELUP,
+       [ 0x74 ] = KEY_VOLUMEUP,
+       [ 0x14 ] = KEY_MUTE,
+
+       [ 0x4c ] = KEY_S,                       /* SVIDEO */
+       [ 0x2c ] = KEY_CHANNELDOWN,
+       [ 0x6c ] = KEY_VOLUMEDOWN,
+       [ 0x0c ] = KEY_ZOOM,
+
+       [ 0x5c ] = KEY_PAUSE,
+       [ 0x3c ] = KEY_C,                       /* || (red) */
+       [ 0x7c ] = KEY_RECORD,          /* recording */
+       [ 0x1c ] = KEY_STOP,
+
+       [ 0x41 ] = KEY_REWIND,          /* backward << */
+       [ 0x21 ] = KEY_PLAY,
+       [ 0x61 ] = KEY_FASTFORWARD,     /* forward >> */
+       [ 0x01 ] = KEY_NEXT,            /* skip >| */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_iodata_bctv7e);
+
+/* ---------------------------------------------------------------------- */
+
+/* ADS Tech Instant TV DVB-T PCI Remote */
+IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
+       /* Keys 0 to 9 */
+       [ 0x4d ] = KEY_0,
+       [ 0x57 ] = KEY_1,
+       [ 0x4f ] = KEY_2,
+       [ 0x53 ] = KEY_3,
+       [ 0x56 ] = KEY_4,
+       [ 0x4e ] = KEY_5,
+       [ 0x5e ] = KEY_6,
+       [ 0x54 ] = KEY_7,
+       [ 0x4c ] = KEY_8,
+       [ 0x5c ] = KEY_9,
+
+       [ 0x5b ] = KEY_POWER,
+       [ 0x5f ] = KEY_MUTE,
+       [ 0x55 ] = KEY_GOTO,
+       [ 0x5d ] = KEY_SEARCH,
+       [ 0x17 ] = KEY_EPG,             /* Guide */
+       [ 0x1f ] = KEY_MENU,
+       [ 0x0f ] = KEY_UP,
+       [ 0x46 ] = KEY_DOWN,
+       [ 0x16 ] = KEY_LEFT,
+       [ 0x1e ] = KEY_RIGHT,
+       [ 0x0e ] = KEY_SELECT,          /* Enter */
+       [ 0x5a ] = KEY_INFO,
+       [ 0x52 ] = KEY_EXIT,
+       [ 0x59 ] = KEY_PREVIOUS,
+       [ 0x51 ] = KEY_NEXT,
+       [ 0x58 ] = KEY_REWIND,
+       [ 0x50 ] = KEY_FORWARD,
+       [ 0x44 ] = KEY_PLAYPAUSE,
+       [ 0x07 ] = KEY_STOP,
+       [ 0x1b ] = KEY_RECORD,
+       [ 0x13 ] = KEY_TUNER,           /* Live */
+       [ 0x0a ] = KEY_A,
+       [ 0x12 ] = KEY_B,
+       [ 0x03 ] = KEY_PROG1,           /* 1 */
+       [ 0x01 ] = KEY_PROG2,           /* 2 */
+       [ 0x00 ] = KEY_PROG3,           /* 3 */
+       [ 0x06 ] = KEY_DVD,
+       [ 0x48 ] = KEY_AUX,             /* Photo */
+       [ 0x40 ] = KEY_VIDEO,
+       [ 0x19 ] = KEY_AUDIO,           /* Music */
+       [ 0x0b ] = KEY_CHANNELUP,
+       [ 0x08 ] = KEY_CHANNELDOWN,
+       [ 0x15 ] = KEY_VOLUMEUP,
+       [ 0x1c ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
+
+/* ---------------------------------------------------------------------- */
+
+/* MSI TV@nywhere remote */
+IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
+       /* Keys 0 to 9 */
+       [ 0x00 ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       [ 0x0c ] = KEY_MUTE,
+       [ 0x0f ] = KEY_SCREEN,          /* Full Screen */
+       [ 0x10 ] = KEY_F,                       /* Funtion */
+       [ 0x11 ] = KEY_T,                       /* Time shift */
+       [ 0x12 ] = KEY_POWER,
+       [ 0x13 ] = KEY_MEDIA,           /* MTS */
+       [ 0x14 ] = KEY_SLOW,
+       [ 0x16 ] = KEY_REWIND,          /* backward << */
+       [ 0x17 ] = KEY_ENTER,           /* Return */
+       [ 0x18 ] = KEY_FASTFORWARD,     /* forward >> */
+       [ 0x1a ] = KEY_CHANNELUP,
+       [ 0x1b ] = KEY_VOLUMEUP,
+       [ 0x1e ] = KEY_CHANNELDOWN,
+       [ 0x1f ] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
+
+/* ---------------------------------------------------------------------- */
+
+/* Cinergy 1400 DVB-T */
+IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
+       [ 0x01 ] = KEY_POWER,
+       [ 0x02 ] = KEY_1,
+       [ 0x03 ] = KEY_2,
+       [ 0x04 ] = KEY_3,
+       [ 0x05 ] = KEY_4,
+       [ 0x06 ] = KEY_5,
+       [ 0x07 ] = KEY_6,
+       [ 0x08 ] = KEY_7,
+       [ 0x09 ] = KEY_8,
+       [ 0x0a ] = KEY_9,
+       [ 0x0c ] = KEY_0,
+
+       [ 0x0b ] = KEY_VIDEO,
+       [ 0x0d ] = KEY_REFRESH,
+       [ 0x0e ] = KEY_SELECT,
+       [ 0x0f ] = KEY_EPG,
+       [ 0x10 ] = KEY_UP,
+       [ 0x11 ] = KEY_LEFT,
+       [ 0x12 ] = KEY_OK,
+       [ 0x13 ] = KEY_RIGHT,
+       [ 0x14 ] = KEY_DOWN,
+       [ 0x15 ] = KEY_TEXT,
+       [ 0x16 ] = KEY_INFO,
+
+       [ 0x17 ] = KEY_RED,
+       [ 0x18 ] = KEY_GREEN,
+       [ 0x19 ] = KEY_YELLOW,
+       [ 0x1a ] = KEY_BLUE,
+
+       [ 0x1b ] = KEY_CHANNELUP,
+       [ 0x1c ] = KEY_VOLUMEUP,
+       [ 0x1d ] = KEY_MUTE,
+       [ 0x1e ] = KEY_VOLUMEDOWN,
+       [ 0x1f ] = KEY_CHANNELDOWN,
+
+       [ 0x40 ] = KEY_PAUSE,
+       [ 0x4c ] = KEY_PLAY,
+       [ 0x58 ] = KEY_RECORD,
+       [ 0x54 ] = KEY_PREVIOUS,
+       [ 0x48 ] = KEY_STOP,
+       [ 0x5c ] = KEY_NEXT,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_cinergy_1400);
+
+/* ---------------------------------------------------------------------- */
+
+/* AVERTV STUDIO 303 Remote */
+IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
+       [ 0x2a ] = KEY_1,
+       [ 0x32 ] = KEY_2,
+       [ 0x3a ] = KEY_3,
+       [ 0x4a ] = KEY_4,
+       [ 0x52 ] = KEY_5,
+       [ 0x5a ] = KEY_6,
+       [ 0x6a ] = KEY_7,
+       [ 0x72 ] = KEY_8,
+       [ 0x7a ] = KEY_9,
+       [ 0x0e ] = KEY_0,
+
+       [ 0x02 ] = KEY_POWER,
+       [ 0x22 ] = KEY_VIDEO,
+       [ 0x42 ] = KEY_AUDIO,
+       [ 0x62 ] = KEY_ZOOM,
+       [ 0x0a ] = KEY_TV,
+       [ 0x12 ] = KEY_CD,
+       [ 0x1a ] = KEY_TEXT,
+
+       [ 0x16 ] = KEY_SUBTITLE,
+       [ 0x1e ] = KEY_REWIND,
+       [ 0x06 ] = KEY_PRINT,
+
+       [ 0x2e ] = KEY_SEARCH,
+       [ 0x36 ] = KEY_SLEEP,
+       [ 0x3e ] = KEY_SHUFFLE,
+       [ 0x26 ] = KEY_MUTE,
+
+       [ 0x4e ] = KEY_RECORD,
+       [ 0x56 ] = KEY_PAUSE,
+       [ 0x5e ] = KEY_STOP,
+       [ 0x46 ] = KEY_PLAY,
+
+       [ 0x6e ] = KEY_RED,
+       [ 0x0b ] = KEY_GREEN,
+       [ 0x66 ] = KEY_YELLOW,
+       [ 0x03 ] = KEY_BLUE,
+
+       [ 0x76 ] = KEY_LEFT,
+       [ 0x7e ] = KEY_RIGHT,
+       [ 0x13 ] = KEY_DOWN,
+       [ 0x1b ] = KEY_UP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avertv_303);
+
+/* ---------------------------------------------------------------------- */
+
+/* DigitalNow DNTV Live! DVB-T Pro Remote */
+IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
+       [ 0x16 ] = KEY_POWER,
+       [ 0x5b ] = KEY_HOME,
+
+       [ 0x55 ] = KEY_TV,              /* live tv */
+       [ 0x58 ] = KEY_TUNER,           /* digital Radio */
+       [ 0x5a ] = KEY_RADIO,           /* FM radio */
+       [ 0x59 ] = KEY_DVD,             /* dvd menu */
+       [ 0x03 ] = KEY_1,
+       [ 0x01 ] = KEY_2,
+       [ 0x06 ] = KEY_3,
+       [ 0x09 ] = KEY_4,
+       [ 0x1d ] = KEY_5,
+       [ 0x1f ] = KEY_6,
+       [ 0x0d ] = KEY_7,
+       [ 0x19 ] = KEY_8,
+       [ 0x1b ] = KEY_9,
+       [ 0x0c ] = KEY_CANCEL,
+       [ 0x15 ] = KEY_0,
+       [ 0x4a ] = KEY_CLEAR,
+       [ 0x13 ] = KEY_BACK,
+       [ 0x00 ] = KEY_TAB,
+       [ 0x4b ] = KEY_UP,
+       [ 0x4e ] = KEY_LEFT,
+       [ 0x4f ] = KEY_OK,
+       [ 0x52 ] = KEY_RIGHT,
+       [ 0x51 ] = KEY_DOWN,
+       [ 0x1e ] = KEY_VOLUMEUP,
+       [ 0x0a ] = KEY_VOLUMEDOWN,
+       [ 0x02 ] = KEY_CHANNELDOWN,
+       [ 0x05 ] = KEY_CHANNELUP,
+       [ 0x11 ] = KEY_RECORD,
+       [ 0x14 ] = KEY_PLAY,
+       [ 0x4c ] = KEY_PAUSE,
+       [ 0x1a ] = KEY_STOP,
+       [ 0x40 ] = KEY_REWIND,
+       [ 0x12 ] = KEY_FASTFORWARD,
+       [ 0x41 ] = KEY_PREVIOUSSONG,    /* replay |< */
+       [ 0x42 ] = KEY_NEXTSONG,        /* skip >| */
+       [ 0x54 ] = KEY_CAMERA,          /* capture */
+       [ 0x50 ] = KEY_LANGUAGE,        /* sap */
+       [ 0x47 ] = KEY_TV2,             /* pip */
+       [ 0x4d ] = KEY_SCREEN,
+       [ 0x43 ] = KEY_SUBTITLE,
+       [ 0x10 ] = KEY_MUTE,
+       [ 0x49 ] = KEY_AUDIO,           /* l/r */
+       [ 0x07 ] = KEY_SLEEP,
+       [ 0x08 ] = KEY_VIDEO,           /* a/v */
+       [ 0x0e ] = KEY_PREVIOUS,        /* recall */
+       [ 0x45 ] = KEY_ZOOM,            /* zoom + */
+       [ 0x46 ] = KEY_ANGLE,           /* zoom - */
+       [ 0x56 ] = KEY_RED,
+       [ 0x57 ] = KEY_GREEN,
+       [ 0x5c ] = KEY_YELLOW,
+       [ 0x5d ] = KEY_BLUE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvbt_pro);
+
+IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
+       [ 0x01 ] = KEY_CHANNEL,
+       [ 0x02 ] = KEY_SELECT,
+       [ 0x03 ] = KEY_MUTE,
+       [ 0x04 ] = KEY_POWER,
+       [ 0x05 ] = KEY_1,
+       [ 0x06 ] = KEY_2,
+       [ 0x07 ] = KEY_3,
+       [ 0x08 ] = KEY_CHANNELUP,
+       [ 0x09 ] = KEY_4,
+       [ 0x0a ] = KEY_5,
+       [ 0x0b ] = KEY_6,
+       [ 0x0c ] = KEY_CHANNELDOWN,
+       [ 0x0d ] = KEY_7,
+       [ 0x0e ] = KEY_8,
+       [ 0x0f ] = KEY_9,
+       [ 0x10 ] = KEY_VOLUMEUP,
+       [ 0x11 ] = KEY_0,
+       [ 0x12 ] = KEY_MENU,
+       [ 0x13 ] = KEY_PRINT,
+       [ 0x14 ] = KEY_VOLUMEDOWN,
+       [ 0x16 ] = KEY_PAUSE,
+       [ 0x18 ] = KEY_RECORD,
+       [ 0x19 ] = KEY_REWIND,
+       [ 0x1a ] = KEY_PLAY,
+       [ 0x1b ] = KEY_FORWARD,
+       [ 0x1c ] = KEY_BACKSPACE,
+       [ 0x1e ] = KEY_STOP,
+       [ 0x40 ] = KEY_ZOOM,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
+
+IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+       [ 0x3a ] = KEY_0,
+       [ 0x31 ] = KEY_1,
+       [ 0x32 ] = KEY_2,
+       [ 0x33 ] = KEY_3,
+       [ 0x34 ] = KEY_4,
+       [ 0x35 ] = KEY_5,
+       [ 0x36 ] = KEY_6,
+       [ 0x37 ] = KEY_7,
+       [ 0x38 ] = KEY_8,
+       [ 0x39 ] = KEY_9,
+
+       [ 0x2f ] = KEY_POWER,
+
+       [ 0x2e ] = KEY_P,
+       [ 0x1f ] = KEY_L,
+       [ 0x2b ] = KEY_I,
+
+       [ 0x2d ] = KEY_ZOOM,
+       [ 0x1e ] = KEY_ZOOM,
+       [ 0x1b ] = KEY_VOLUMEUP,
+       [ 0x0f ] = KEY_VOLUMEDOWN,
+       [ 0x17 ] = KEY_CHANNELUP,
+       [ 0x1c ] = KEY_CHANNELDOWN,
+       [ 0x25 ] = KEY_INFO,
+
+       [ 0x3c ] = KEY_MUTE,
+
+       [ 0x3d ] = KEY_LEFT,
+       [ 0x3b ] = KEY_RIGHT,
+
+       [ 0x3f ] = KEY_UP,
+       [ 0x3e ] = KEY_DOWN,
+       [ 0x1a ] = KEY_PAUSE,
+
+       [ 0x1d ] = KEY_MENU,
+       [ 0x19 ] = KEY_PLAY,
+       [ 0x16 ] = KEY_REWIND,
+       [ 0x13 ] = KEY_FORWARD,
+       [ 0x15 ] = KEY_PAUSE,
+       [ 0x0e ] = KEY_REWIND,
+       [ 0x0d ] = KEY_PLAY,
+       [ 0x0b ] = KEY_STOP,
+       [ 0x07 ] = KEY_FORWARD,
+       [ 0x27 ] = KEY_RECORD,
+       [ 0x26 ] = KEY_TUNER,
+       [ 0x29 ] = KEY_TEXT,
+       [ 0x2a ] = KEY_MEDIA,
+       [ 0x18 ] = KEY_EPG,
+       [ 0x27 ] = KEY_RECORD,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+
+IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
+       [ 0x0f ] = KEY_0,
+       [ 0x03 ] = KEY_1,
+       [ 0x04 ] = KEY_2,
+       [ 0x05 ] = KEY_3,
+       [ 0x07 ] = KEY_4,
+       [ 0x08 ] = KEY_5,
+       [ 0x09 ] = KEY_6,
+       [ 0x0b ] = KEY_7,
+       [ 0x0c ] = KEY_8,
+       [ 0x0d ] = KEY_9,
+
+       [ 0x0e ] = KEY_MODE,         // Air/Cable
+       [ 0x11 ] = KEY_VIDEO,        // Video
+       [ 0x15 ] = KEY_AUDIO,        // Audio
+       [ 0x00 ] = KEY_POWER,        // Power
+       [ 0x18 ] = KEY_TUNER,        // AV Source
+       [ 0x02 ] = KEY_ZOOM,         // Fullscreen
+       [ 0x1a ] = KEY_LANGUAGE,     // Stereo
+       [ 0x1b ] = KEY_MUTE,         // Mute
+       [ 0x14 ] = KEY_VOLUMEUP,     // Volume +
+       [ 0x17 ] = KEY_VOLUMEDOWN,   // Volume -
+       [ 0x12 ] = KEY_CHANNELUP,    // Channel +
+       [ 0x13 ] = KEY_CHANNELDOWN,  // Channel -
+       [ 0x06 ] = KEY_AGAIN,        // Recall
+       [ 0x10 ] = KEY_ENTER,      // Enter
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_flyvideo);
+
+IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE] = {
+       [ 0x01 ] = KEY_ZOOM,            // Full Screen
+       [ 0x00 ] = KEY_POWER,           // Power
+
+       [ 0x03 ] = KEY_1,
+       [ 0x04 ] = KEY_2,
+       [ 0x05 ] = KEY_3,
+       [ 0x07 ] = KEY_4,
+       [ 0x08 ] = KEY_5,
+       [ 0x09 ] = KEY_6,
+       [ 0x0b ] = KEY_7,
+       [ 0x0c ] = KEY_8,
+       [ 0x0d ] = KEY_9,
+       [ 0x06 ] = KEY_AGAIN,           // Recall
+       [ 0x0f ] = KEY_0,
+       [ 0x10 ] = KEY_MUTE,            // Mute
+       [ 0x02 ] = KEY_RADIO,           // TV/Radio
+       [ 0x1b ] = KEY_LANGUAGE,                // SAP (Second Audio Program)
+
+       [ 0x14 ] = KEY_VOLUMEUP,                // VOL+
+       [ 0x17 ] = KEY_VOLUMEDOWN,      // VOL-
+       [ 0x12 ] = KEY_CHANNELUP,               // CH+
+       [ 0x13 ] = KEY_CHANNELDOWN,     // CH-
+       [ 0x1d ] = KEY_ENTER,           // Enter
+
+       [ 0x1a ] = KEY_MODE,            // PIP
+       [ 0x18 ] = KEY_TUNER,           // Source
+
+       [ 0x1e ] = KEY_RECORD,          // Record/Pause
+       [ 0x15 ] = KEY_ANGLE,           // Swap (no label on key)
+       [ 0x1c ] = KEY_PAUSE,           // Timeshift/Pause
+       [ 0x19 ] = KEY_BACK,            // Rewind <<
+       [ 0x0a ] = KEY_PLAYPAUSE,               // Play/Pause
+       [ 0x1f ] = KEY_FORWARD,         // Forward >>
+       [ 0x16 ] = KEY_PREVIOUS,                // Back |<<
+       [ 0x11 ] = KEY_STOP,            // Stop
+       [ 0x0e ] = KEY_NEXT,            // End >>|
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_flydvb);
+
+IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE] = {
+       [ 0x00 ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       [ 0x0a ] = KEY_POWER,
+       [ 0x0b ] = KEY_PROG1,           // app
+       [ 0x0c ] = KEY_ZOOM,            // zoom/fullscreen
+       [ 0x0d ] = KEY_CHANNELUP,       // channel
+       [ 0x0e ] = KEY_CHANNELDOWN,     // channel-
+       [ 0x0f ] = KEY_VOLUMEUP,
+       [ 0x10 ] = KEY_VOLUMEDOWN,
+       [ 0x11 ] = KEY_TUNER,           // AV
+       [ 0x12 ] = KEY_NUMLOCK,         // -/--
+       [ 0x13 ] = KEY_AUDIO,           // audio
+       [ 0x14 ] = KEY_MUTE,
+       [ 0x15 ] = KEY_UP,
+       [ 0x16 ] = KEY_DOWN,
+       [ 0x17 ] = KEY_LEFT,
+       [ 0x18 ] = KEY_RIGHT,
+       [ 0x19 ] = BTN_LEFT,
+       [ 0x1a ] = BTN_RIGHT,
+       [ 0x1b ] = KEY_WWW,             // text
+       [ 0x1c ] = KEY_REWIND,
+       [ 0x1d ] = KEY_FORWARD,
+       [ 0x1e ] = KEY_RECORD,
+       [ 0x1f ] = KEY_PLAY,
+       [ 0x20 ] = KEY_PREVIOUSSONG,
+       [ 0x21 ] = KEY_NEXTSONG,
+       [ 0x22 ] = KEY_PAUSE,
+       [ 0x23 ] = KEY_STOP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_cinergy);
+
+/* Alfons Geser <a.geser@cox.net>
+ * updates from Job D. R. Borges <jobdrb@ig.com.br> */
+IR_KEYTAB_TYPE ir_codes_eztv[IR_KEYTAB_SIZE] = {
+       [ 0x12 ] = KEY_POWER,
+       [ 0x01 ] = KEY_TV,             // DVR
+       [ 0x15 ] = KEY_DVD,            // DVD
+       [ 0x17 ] = KEY_AUDIO,          // music
+                                    // DVR mode / DVD mode / music mode
+
+       [ 0x1b ] = KEY_MUTE,           // mute
+       [ 0x02 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
+       [ 0x1e ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
+       [ 0x16 ] = KEY_ZOOM,           // full screen
+       [ 0x1c ] = KEY_VIDEO,          // video source / eject / delall
+       [ 0x1d ] = KEY_RESTART,        // playback / angle / del
+       [ 0x2f ] = KEY_SEARCH,         // scan / menu / playlist
+       [ 0x30 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
+
+       [ 0x31 ] = KEY_HELP,           // help
+       [ 0x32 ] = KEY_MODE,           // num/memo
+       [ 0x33 ] = KEY_ESC,            // cancel
+
+       [ 0x0c ] = KEY_UP,             // up
+       [ 0x10 ] = KEY_DOWN,           // down
+       [ 0x08 ] = KEY_LEFT,           // left
+       [ 0x04 ] = KEY_RIGHT,          // right
+       [ 0x03 ] = KEY_SELECT,         // select
+
+       [ 0x1f ] = KEY_REWIND,         // rewind
+       [ 0x20 ] = KEY_PLAYPAUSE,      // play/pause
+       [ 0x29 ] = KEY_FORWARD,        // forward
+       [ 0x14 ] = KEY_AGAIN,          // repeat
+       [ 0x2b ] = KEY_RECORD,         // recording
+       [ 0x2c ] = KEY_STOP,           // stop
+       [ 0x2d ] = KEY_PLAY,           // play
+       [ 0x2e ] = KEY_SHUFFLE,        // snapshot / shuffle
+
+       [ 0x00 ] = KEY_0,
+       [ 0x05 ] = KEY_1,
+       [ 0x06 ] = KEY_2,
+       [ 0x07 ] = KEY_3,
+       [ 0x09 ] = KEY_4,
+       [ 0x0a ] = KEY_5,
+       [ 0x0b ] = KEY_6,
+       [ 0x0d ] = KEY_7,
+       [ 0x0e ] = KEY_8,
+       [ 0x0f ] = KEY_9,
+
+       [ 0x2a ] = KEY_VOLUMEUP,
+       [ 0x11 ] = KEY_VOLUMEDOWN,
+       [ 0x18 ] = KEY_CHANNELUP,      // CH.tracking up
+       [ 0x19 ] = KEY_CHANNELDOWN,    // CH.tracking down
+
+       [ 0x13 ] = KEY_ENTER,        // enter
+       [ 0x21 ] = KEY_DOT,          // . (decimal dot)
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_eztv);
+
+/* Alex Hermann <gaaf@gmx.net> */
+IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = {
+       [ 0x28 ] = KEY_1,
+       [ 0x18 ] = KEY_2,
+       [ 0x38 ] = KEY_3,
+       [ 0x24 ] = KEY_4,
+       [ 0x14 ] = KEY_5,
+       [ 0x34 ] = KEY_6,
+       [ 0x2c ] = KEY_7,
+       [ 0x1c ] = KEY_8,
+       [ 0x3c ] = KEY_9,
+       [ 0x22 ] = KEY_0,
+
+       [ 0x20 ] = KEY_TV,              /* TV/FM */
+       [ 0x10 ] = KEY_CD,              /* CD */
+       [ 0x30 ] = KEY_TEXT,            /* TELETEXT */
+       [ 0x00 ] = KEY_POWER,           /* POWER */
+
+       [ 0x08 ] = KEY_VIDEO,           /* VIDEO */
+       [ 0x04 ] = KEY_AUDIO,           /* AUDIO */
+       [ 0x0c ] = KEY_ZOOM,            /* FULL SCREEN */
+
+       [ 0x12 ] = KEY_SUBTITLE,        /* DISPLAY */
+       [ 0x32 ] = KEY_REWIND,          /* LOOP */
+       [ 0x02 ] = KEY_PRINT,           /* PREVIEW */
+
+       [ 0x2a ] = KEY_SEARCH,          /* AUTOSCAN */
+       [ 0x1a ] = KEY_SLEEP,           /* FREEZE */
+       [ 0x3a ] = KEY_SHUFFLE,         /* SNAPSHOT */
+       [ 0x0a ] = KEY_MUTE,            /* MUTE */
+
+       [ 0x26 ] = KEY_RECORD,          /* RECORD */
+       [ 0x16 ] = KEY_PAUSE,           /* PAUSE */
+       [ 0x36 ] = KEY_STOP,            /* STOP */
+       [ 0x06 ] = KEY_PLAY,            /* PLAY */
+
+       [ 0x2e ] = KEY_RED,             /* RED */
+       [ 0x21 ] = KEY_GREEN,           /* GREEN */
+       [ 0x0e ] = KEY_YELLOW,          /* YELLOW */
+       [ 0x01 ] = KEY_BLUE,            /* BLUE */
+
+       [ 0x1e ] = KEY_VOLUMEDOWN,      /* VOLUME- */
+       [ 0x3e ] = KEY_VOLUMEUP,        /* VOLUME+ */
+       [ 0x11 ] = KEY_CHANNELDOWN,     /* CHANNEL/PAGE- */
+       [ 0x31 ] = KEY_CHANNELUP        /* CHANNEL/PAGE+ */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_avermedia);
+
+IR_KEYTAB_TYPE ir_codes_videomate_tv_pvr[IR_KEYTAB_SIZE] = {
+       [ 0x14 ] = KEY_MUTE,
+       [ 0x24 ] = KEY_ZOOM,
+
+       [ 0x01 ] = KEY_DVD,
+       [ 0x23 ] = KEY_RADIO,
+       [ 0x00 ] = KEY_TV,
+
+       [ 0x0a ] = KEY_REWIND,
+       [ 0x08 ] = KEY_PLAYPAUSE,
+       [ 0x0f ] = KEY_FORWARD,
+
+       [ 0x02 ] = KEY_PREVIOUS,
+       [ 0x07 ] = KEY_STOP,
+       [ 0x06 ] = KEY_NEXT,
+
+       [ 0x0c ] = KEY_UP,
+       [ 0x0e ] = KEY_DOWN,
+       [ 0x0b ] = KEY_LEFT,
+       [ 0x0d ] = KEY_RIGHT,
+       [ 0x11 ] = KEY_OK,
+
+       [ 0x03 ] = KEY_MENU,
+       [ 0x09 ] = KEY_SETUP,
+       [ 0x05 ] = KEY_VIDEO,
+       [ 0x22 ] = KEY_CHANNEL,
+
+       [ 0x12 ] = KEY_VOLUMEUP,
+       [ 0x15 ] = KEY_VOLUMEDOWN,
+       [ 0x10 ] = KEY_CHANNELUP,
+       [ 0x13 ] = KEY_CHANNELDOWN,
+
+       [ 0x04 ] = KEY_RECORD,
+
+       [ 0x16 ] = KEY_1,
+       [ 0x17 ] = KEY_2,
+       [ 0x18 ] = KEY_3,
+       [ 0x19 ] = KEY_4,
+       [ 0x1a ] = KEY_5,
+       [ 0x1b ] = KEY_6,
+       [ 0x1c ] = KEY_7,
+       [ 0x1d ] = KEY_8,
+       [ 0x1e ] = KEY_9,
+       [ 0x1f ] = KEY_0,
+
+       [ 0x20 ] = KEY_LANGUAGE,
+       [ 0x21 ] = KEY_SLEEP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_videomate_tv_pvr);
+
+/* Michael Tokarev <mjt@tls.msk.ru>
+   http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
+   keytable is used by MANLI MTV00[ 0x0c ] and BeholdTV 40[13] at
+   least, and probably other cards too.
+   The "ascii-art picture" below (in comments, first row
+   is the keycode in hex, and subsequent row(s) shows
+   the button labels (several variants when appropriate)
+   helps to descide which keycodes to assign to the buttons.
+ */
+IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE] = {
+
+       /*  0x1c            0x12  *
+        * FUNCTION         POWER *
+        *   FM              (|)  *
+        *                        */
+       [ 0x1c ] = KEY_RADIO,   /*XXX*/
+       [ 0x12 ] = KEY_POWER,
+
+       /*  0x01    0x02    0x03  *
+        *   1       2       3    *
+        *                        *
+        *  0x04    0x05    0x06  *
+        *   4       5       6    *
+        *                        *
+        *  0x07    0x08    0x09  *
+        *   7       8       9    *
+        *                        */
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       /*  0x0a    0x00    0x17  *
+        * RECALL    0      +100  *
+        *                  PLUS  *
+        *                        */
+       [ 0x0a ] = KEY_AGAIN,   /*XXX KEY_REWIND? */
+       [ 0x00 ] = KEY_0,
+       [ 0x17 ] = KEY_DIGITS,  /*XXX*/
+
+       /*  0x14            0x10  *
+        *  MENU            INFO  *
+        *  OSD                   */
+       [ 0x14 ] = KEY_MENU,
+       [ 0x10 ] = KEY_INFO,
+
+       /*          0x0b          *
+        *           Up           *
+        *                        *
+        *  0x18    0x16    0x0c  *
+        *  Left     Ok     Right *
+        *                        *
+        *         0x015          *
+        *         Down           *
+        *                        */
+       [ 0x0b ] = KEY_UP,      /*XXX KEY_SCROLLUP? */
+       [ 0x18 ] = KEY_LEFT,    /*XXX KEY_BACK? */
+       [ 0x16 ] = KEY_OK,      /*XXX KEY_SELECT? KEY_ENTER? */
+       [ 0x0c ] = KEY_RIGHT,   /*XXX KEY_FORWARD? */
+       [ 0x15 ] = KEY_DOWN,    /*XXX KEY_SCROLLDOWN? */
+
+       /*  0x11            0x0d  *
+        *  TV/AV           MODE  *
+        *  SOURCE         STEREO *
+        *                        */
+       [ 0x11 ] = KEY_TV,      /*XXX*/
+       [ 0x0d ] = KEY_MODE,    /*XXX there's no KEY_STEREO */
+
+       /*  0x0f    0x1b    0x1a  *
+        *  AUDIO   Vol+    Chan+ *
+        *        TIMESHIFT???    *
+        *                        *
+        *  0x0e    0x1f    0x1e  *
+        *  SLEEP   Vol-    Chan- *
+        *                        */
+       [ 0x0f ] = KEY_AUDIO,
+       [ 0x1b ] = KEY_VOLUMEUP,
+       [ 0x1a ] = KEY_CHANNELUP,
+       [ 0x0e ] = KEY_SLEEP,   /*XXX maybe KEY_PAUSE */
+       [ 0x1f ] = KEY_VOLUMEDOWN,
+       [ 0x1e ] = KEY_CHANNELDOWN,
+
+       /*         0x13     0x19  *
+        *         MUTE   SNAPSHOT*
+        *                        */
+       [ 0x13 ] = KEY_MUTE,
+       [ 0x19 ] = KEY_RECORD,  /*XXX*/
+
+       // 0x1d unused ?
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_manli);
+
+/* Mike Baikov <mike@baikov.com> */
+IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE] = {
+
+       [ 0x21 ] = KEY_POWER,
+       [ 0x69 ] = KEY_TV,
+       [ 0x33 ] = KEY_0,
+       [ 0x51 ] = KEY_1,
+       [ 0x31 ] = KEY_2,
+       [ 0x71 ] = KEY_3,
+       [ 0x3b ] = KEY_4,
+       [ 0x58 ] = KEY_5,
+       [ 0x41 ] = KEY_6,
+       [ 0x48 ] = KEY_7,
+       [ 0x30 ] = KEY_8,
+       [ 0x53 ] = KEY_9,
+       [ 0x73 ] = KEY_AGAIN, /* LOOP */
+       [ 0x0a ] = KEY_AUDIO,
+       [ 0x61 ] = KEY_PRINT, /* PREVIEW */
+       [ 0x7a ] = KEY_VIDEO,
+       [ 0x20 ] = KEY_CHANNELUP,
+       [ 0x40 ] = KEY_CHANNELDOWN,
+       [ 0x18 ] = KEY_VOLUMEDOWN,
+       [ 0x50 ] = KEY_VOLUMEUP,
+       [ 0x10 ] = KEY_MUTE,
+       [ 0x4a ] = KEY_SEARCH,
+       [ 0x7b ] = KEY_SHUFFLE, /* SNAPSHOT */
+       [ 0x22 ] = KEY_RECORD,
+       [ 0x62 ] = KEY_STOP,
+       [ 0x78 ] = KEY_PLAY,
+       [ 0x39 ] = KEY_REWIND,
+       [ 0x59 ] = KEY_PAUSE,
+       [ 0x19 ] = KEY_FORWARD,
+       [ 0x09 ] = KEY_ZOOM,
+
+       [ 0x52 ] = KEY_F21, /* LIVE TIMESHIFT */
+       [ 0x1a ] = KEY_F22, /* MIN TIMESHIFT */
+       [ 0x3a ] = KEY_F23, /* TIMESHIFT */
+       [ 0x70 ] = KEY_F24, /* NORMAL TIMESHIFT */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_gotview7135);
+
+IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
+       [ 0x03 ] = KEY_POWER,
+       [ 0x6f ] = KEY_MUTE,
+       [ 0x10 ] = KEY_BACKSPACE,       /* Recall */
+
+       [ 0x11 ] = KEY_0,
+       [ 0x04 ] = KEY_1,
+       [ 0x05 ] = KEY_2,
+       [ 0x06 ] = KEY_3,
+       [ 0x08 ] = KEY_4,
+       [ 0x09 ] = KEY_5,
+       [ 0x0a ] = KEY_6,
+       [ 0x0c ] = KEY_7,
+       [ 0x0d ] = KEY_8,
+       [ 0x0e ] = KEY_9,
+       [ 0x12 ] = KEY_DOT,           /* 100+ */
+
+       [ 0x07 ] = KEY_VOLUMEUP,
+       [ 0x0b ] = KEY_VOLUMEDOWN,
+       [ 0x1a ] = KEY_KPPLUS,
+       [ 0x18 ] = KEY_KPMINUS,
+       [ 0x15 ] = KEY_UP,
+       [ 0x1d ] = KEY_DOWN,
+       [ 0x0f ] = KEY_CHANNELUP,
+       [ 0x13 ] = KEY_CHANNELDOWN,
+       [ 0x48 ] = KEY_ZOOM,
+
+       [ 0x1b ] = KEY_VIDEO,           /* Video source */
+       [ 0x49 ] = KEY_LANGUAGE,        /* MTS Select */
+       [ 0x19 ] = KEY_SEARCH,          /* Auto Scan */
+
+       [ 0x4b ] = KEY_RECORD,
+       [ 0x46 ] = KEY_PLAY,
+       [ 0x45 ] = KEY_PAUSE,           /* Pause */
+       [ 0x44 ] = KEY_STOP,
+       [ 0x40 ] = KEY_FORWARD,         /* Forward ? */
+       [ 0x42 ] = KEY_REWIND,          /* Backward ? */
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_purpletv);
+
+/* Mapping for the 28 key remote control as seen at
+   http://www.sednacomputer.com/photo/cardbus-tv.jpg
+   Pavel Mihaylov <bin@bash.info> */
+IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE] = {
+       [ 0x00 ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       [ 0x0a ] = KEY_AGAIN,          /* Recall */
+       [ 0x0b ] = KEY_CHANNELUP,
+       [ 0x0c ] = KEY_VOLUMEUP,
+       [ 0x0d ] = KEY_MODE,           /* Stereo */
+       [ 0x0e ] = KEY_STOP,
+       [ 0x0f ] = KEY_PREVIOUSSONG,
+       [ 0x10 ] = KEY_ZOOM,
+       [ 0x11 ] = KEY_TUNER,          /* Source */
+       [ 0x12 ] = KEY_POWER,
+       [ 0x13 ] = KEY_MUTE,
+       [ 0x15 ] = KEY_CHANNELDOWN,
+       [ 0x18 ] = KEY_VOLUMEDOWN,
+       [ 0x19 ] = KEY_SHUFFLE,        /* Snapshot */
+       [ 0x1a ] = KEY_NEXTSONG,
+       [ 0x1b ] = KEY_TEXT,           /* Time Shift */
+       [ 0x1c ] = KEY_RADIO,          /* FM Radio */
+       [ 0x1d ] = KEY_RECORD,
+       [ 0x1e ] = KEY_PAUSE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna);
+
+/* Mark Phalan <phalanm@o2.ie> */
+IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
+       [ 0x00 ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       [ 0x12 ] = KEY_POWER,
+       [ 0x10 ] = KEY_MUTE,
+       [ 0x1f ] = KEY_VOLUMEDOWN,
+       [ 0x1b ] = KEY_VOLUMEUP,
+       [ 0x1a ] = KEY_CHANNELUP,
+       [ 0x1e ] = KEY_CHANNELDOWN,
+       [ 0x0e ] = KEY_PAGEUP,
+       [ 0x1d ] = KEY_PAGEDOWN,
+       [ 0x13 ] = KEY_SOUND,
+
+       [ 0x18 ] = KEY_KPPLUSMINUS,     /* CH +/- */
+       [ 0x16 ] = KEY_SUBTITLE,                /* CC */
+       [ 0x0d ] = KEY_TEXT,            /* TTX */
+       [ 0x0b ] = KEY_TV,              /* AIR/CBL */
+       [ 0x11 ] = KEY_PC,              /* PC/TV */
+       [ 0x17 ] = KEY_OK,              /* CH RTN */
+       [ 0x19 ] = KEY_MODE,            /* FUNC */
+       [ 0x0c ] = KEY_SEARCH,          /* AUTOSCAN */
+
+       /* Not sure what to do with these ones! */
+       [ 0x0f ] = KEY_SELECT,          /* SOURCE */
+       [ 0x0a ] = KEY_KPPLUS,          /* +100 */
+       [ 0x14 ] = KEY_EQUAL,           /* SYNC */
+       [ 0x1c ] = KEY_MEDIA,             /* PC/TV */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pv951);
+
+/* generic RC5 keytable                                          */
+/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
+/* used by old (black) Hauppauge remotes                         */
+IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
+       /* Keys 0 to 9 */
+       [ 0x00 ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       [ 0x0b ] = KEY_CHANNEL,         /* channel / program (japan: 11) */
+       [ 0x0c ] = KEY_POWER,           /* standby */
+       [ 0x0d ] = KEY_MUTE,            /* mute / demute */
+       [ 0x0f ] = KEY_TV,              /* display */
+       [ 0x10 ] = KEY_VOLUMEUP,
+       [ 0x11 ] = KEY_VOLUMEDOWN,
+       [ 0x12 ] = KEY_BRIGHTNESSUP,
+       [ 0x13 ] = KEY_BRIGHTNESSDOWN,
+       [ 0x1e ] = KEY_SEARCH,          /* search + */
+       [ 0x20 ] = KEY_CHANNELUP,       /* channel / program + */
+       [ 0x21 ] = KEY_CHANNELDOWN,     /* channel / program - */
+       [ 0x22 ] = KEY_CHANNEL,         /* alt / channel */
+       [ 0x23 ] = KEY_LANGUAGE,        /* 1st / 2nd language */
+       [ 0x26 ] = KEY_SLEEP,           /* sleeptimer */
+       [ 0x2e ] = KEY_MENU,            /* 2nd controls (USA: menu) */
+       [ 0x30 ] = KEY_PAUSE,
+       [ 0x32 ] = KEY_REWIND,
+       [ 0x33 ] = KEY_GOTO,
+       [ 0x35 ] = KEY_PLAY,
+       [ 0x36 ] = KEY_STOP,
+       [ 0x37 ] = KEY_RECORD,          /* recording */
+       [ 0x3c ] = KEY_TEXT,            /* teletext submode (Japan: 12) */
+       [ 0x3d ] = KEY_SUSPEND,         /* system standby */
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
+
+/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
+IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
+       /* Keys 0 to 9 */
+       [ 0x12 ] = KEY_0,
+       [ 0x05 ] = KEY_1,
+       [ 0x06 ] = KEY_2,
+       [ 0x07 ] = KEY_3,
+       [ 0x09 ] = KEY_4,
+       [ 0x0a ] = KEY_5,
+       [ 0x0b ] = KEY_6,
+       [ 0x0d ] = KEY_7,
+       [ 0x0e ] = KEY_8,
+       [ 0x0f ] = KEY_9,
+
+       [ 0x00 ] = KEY_POWER,
+       [ 0x02 ] = KEY_TUNER,           /* TV/FM */
+       [ 0x1e ] = KEY_VIDEO,
+       [ 0x04 ] = KEY_VOLUMEUP,
+       [ 0x08 ] = KEY_VOLUMEDOWN,
+       [ 0x0c ] = KEY_CHANNELUP,
+       [ 0x10 ] = KEY_CHANNELDOWN,
+       [ 0x03 ] = KEY_ZOOM,            /* fullscreen */
+       [ 0x1f ] = KEY_SUBTITLE,                /* closed caption/teletext */
+       [ 0x20 ] = KEY_SLEEP,
+       [ 0x14 ] = KEY_MUTE,
+       [ 0x2b ] = KEY_RED,
+       [ 0x2c ] = KEY_GREEN,
+       [ 0x2d ] = KEY_YELLOW,
+       [ 0x2e ] = KEY_BLUE,
+       [ 0x18 ] = KEY_KPPLUS,          /* fine tune + */
+       [ 0x19 ] = KEY_KPMINUS,         /* fine tune - */
+       [ 0x21 ] = KEY_DOT,
+       [ 0x13 ] = KEY_ENTER,
+       [ 0x22 ] = KEY_BACK,
+       [ 0x23 ] = KEY_PLAYPAUSE,
+       [ 0x24 ] = KEY_NEXT,
+       [ 0x26 ] = KEY_STOP,
+       [ 0x27 ] = KEY_RECORD
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_winfast);
+
+IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+       [ 0x59 ] = KEY_MUTE,
+       [ 0x4a ] = KEY_POWER,
+
+       [ 0x18 ] = KEY_TEXT,
+       [ 0x26 ] = KEY_TV,
+       [ 0x3d ] = KEY_PRINT,
+
+       [ 0x48 ] = KEY_RED,
+       [ 0x04 ] = KEY_GREEN,
+       [ 0x11 ] = KEY_YELLOW,
+       [ 0x00 ] = KEY_BLUE,
+
+       [ 0x2d ] = KEY_VOLUMEUP,
+       [ 0x1e ] = KEY_VOLUMEDOWN,
+
+       [ 0x49 ] = KEY_MENU,
+
+       [ 0x16 ] = KEY_CHANNELUP,
+       [ 0x17 ] = KEY_CHANNELDOWN,
+
+       [ 0x20 ] = KEY_UP,
+       [ 0x21 ] = KEY_DOWN,
+       [ 0x22 ] = KEY_LEFT,
+       [ 0x23 ] = KEY_RIGHT,
+       [ 0x0d ] = KEY_SELECT,
+
+
+
+       [ 0x08 ] = KEY_BACK,
+       [ 0x07 ] = KEY_REFRESH,
+
+       [ 0x2f ] = KEY_ZOOM,
+       [ 0x29 ] = KEY_RECORD,
+
+       [ 0x4b ] = KEY_PAUSE,
+       [ 0x4d ] = KEY_REWIND,
+       [ 0x2e ] = KEY_PLAY,
+       [ 0x4e ] = KEY_FORWARD,
+       [ 0x53 ] = KEY_PREVIOUS,
+       [ 0x4c ] = KEY_STOP,
+       [ 0x54 ] = KEY_NEXT,
+
+       [ 0x69 ] = KEY_0,
+       [ 0x6a ] = KEY_1,
+       [ 0x6b ] = KEY_2,
+       [ 0x6c ] = KEY_3,
+       [ 0x6d ] = KEY_4,
+       [ 0x6e ] = KEY_5,
+       [ 0x6f ] = KEY_6,
+       [ 0x70 ] = KEY_7,
+       [ 0x71 ] = KEY_8,
+       [ 0x72 ] = KEY_9,
+
+       [ 0x74 ] = KEY_CHANNEL,
+       [ 0x0a ] = KEY_BACKSPACE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+
+/* Hauppauge: the newer, gray remotes (seems there are multiple
+ * slightly different versions), shipped with cx88+ivtv cards.
+ * almost rc5 coding, but some non-standard keys */
+IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
+       /* Keys 0 to 9 */
+       [ 0x00 ] = KEY_0,
+       [ 0x01 ] = KEY_1,
+       [ 0x02 ] = KEY_2,
+       [ 0x03 ] = KEY_3,
+       [ 0x04 ] = KEY_4,
+       [ 0x05 ] = KEY_5,
+       [ 0x06 ] = KEY_6,
+       [ 0x07 ] = KEY_7,
+       [ 0x08 ] = KEY_8,
+       [ 0x09 ] = KEY_9,
+
+       [ 0x0a ] = KEY_TEXT,            /* keypad asterisk as well */
+       [ 0x0b ] = KEY_RED,             /* red button */
+       [ 0x0c ] = KEY_RADIO,
+       [ 0x0d ] = KEY_MENU,
+       [ 0x0e ] = KEY_SUBTITLE,        /* also the # key */
+       [ 0x0f ] = KEY_MUTE,
+       [ 0x10 ] = KEY_VOLUMEUP,
+       [ 0x11 ] = KEY_VOLUMEDOWN,
+       [ 0x12 ] = KEY_PREVIOUS,        /* previous channel */
+       [ 0x14 ] = KEY_UP,
+       [ 0x15 ] = KEY_DOWN,
+       [ 0x16 ] = KEY_LEFT,
+       [ 0x17 ] = KEY_RIGHT,
+       [ 0x18 ] = KEY_VIDEO,           /* Videos */
+       [ 0x19 ] = KEY_AUDIO,           /* Music */
+       /* 0x1a: Pictures - presume this means
+          "Multimedia Home Platform" -
+          no "PICTURES" key in input.h
+        */
+       [ 0x1a ] = KEY_MHP,
+
+       [ 0x1b ] = KEY_EPG,             /* Guide */
+       [ 0x1c ] = KEY_TV,
+       [ 0x1e ] = KEY_NEXTSONG,        /* skip >| */
+       [ 0x1f ] = KEY_EXIT,            /* back/exit */
+       [ 0x20 ] = KEY_CHANNELUP,       /* channel / program + */
+       [ 0x21 ] = KEY_CHANNELDOWN,     /* channel / program - */
+       [ 0x22 ] = KEY_CHANNEL,         /* source (old black remote) */
+       [ 0x24 ] = KEY_PREVIOUSSONG,    /* replay |< */
+       [ 0x25 ] = KEY_ENTER,           /* OK */
+       [ 0x26 ] = KEY_SLEEP,           /* minimize (old black remote) */
+       [ 0x29 ] = KEY_BLUE,            /* blue key */
+       [ 0x2e ] = KEY_GREEN,           /* green button */
+       [ 0x30 ] = KEY_PAUSE,           /* pause */
+       [ 0x32 ] = KEY_REWIND,          /* backward << */
+       [ 0x34 ] = KEY_FASTFORWARD,     /* forward >> */
+       [ 0x35 ] = KEY_PLAY,
+       [ 0x36 ] = KEY_STOP,
+       [ 0x37 ] = KEY_RECORD,          /* recording */
+       [ 0x38 ] = KEY_YELLOW,          /* yellow key */
+       [ 0x3b ] = KEY_SELECT,          /* top right button */
+       [ 0x3c ] = KEY_ZOOM,            /* full */
+       [ 0x3d ] = KEY_POWER,           /* system power (green button) */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
+
index 04c1938..8cdd4d2 100644 (file)
@@ -21,7 +21,7 @@
 #include <media/saa7146.h>
 
 LIST_HEAD(saa7146_devices);
-DECLARE_MUTEX(saa7146_devices_lock);
+DEFINE_MUTEX(saa7146_devices_lock);
 
 static int saa7146_num;
 
@@ -116,8 +116,7 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
                pg = vmalloc_to_page(virt);
                if (NULL == pg)
                        goto err;
-               if (PageHighMem(pg))
-                       BUG();
+               BUG_ON(PageHighMem(pg));
                sglist[i].page   = pg;
                sglist[i].length = PAGE_SIZE;
        }
@@ -402,11 +401,11 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
 
        pci_set_drvdata(pci, dev);
 
-       init_MUTEX(&dev->lock);
+       mutex_init(&dev->lock);
        spin_lock_init(&dev->int_slock);
        spin_lock_init(&dev->slock);
 
-       init_MUTEX(&dev->i2c_lock);
+       mutex_init(&dev->i2c_lock);
 
        dev->module = THIS_MODULE;
        init_waitqueue_head(&dev->i2c_wq);
index f8cf73e..3870fa9 100644 (file)
@@ -17,18 +17,18 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
        }
 
        /* is it free? */
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        if (vv->resources & bit) {
                DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
                /* no, someone else uses it */
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
        fh->resources  |= bit;
        vv->resources |= bit;
        DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        return 1;
 }
 
@@ -37,14 +37,13 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
        struct saa7146_dev *dev = fh->dev;
        struct saa7146_vv *vv = dev->vv_data;
 
-       if ((fh->resources & bits) != bits)
-               BUG();
+       BUG_ON((fh->resources & bits) != bits);
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        fh->resources  &= ~bits;
        vv->resources &= ~bits;
        DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 }
 
 
@@ -55,8 +54,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct saa7146_buf *buf)
 {
        DEB_EE(("dev:%p, buf:%p\n",dev,buf));
 
-       if (in_interrupt())
-               BUG();
+       BUG_ON(in_interrupt());
 
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
@@ -204,7 +202,7 @@ static int fops_open(struct inode *inode, struct file *file)
 
        DEB_EE(("inode:%p, file:%p, minor:%d\n",inode,file,minor));
 
-       if (down_interruptible(&saa7146_devices_lock))
+       if (mutex_lock_interruptible(&saa7146_devices_lock))
                return -ERESTARTSYS;
 
        list_for_each(list,&saa7146_devices) {
@@ -276,7 +274,7 @@ out:
                kfree(fh);
                file->private_data = NULL;
        }
-       up(&saa7146_devices_lock);
+       mutex_unlock(&saa7146_devices_lock);
        return result;
 }
 
@@ -287,7 +285,7 @@ static int fops_release(struct inode *inode, struct file *file)
 
        DEB_EE(("inode:%p, file:%p\n",inode,file));
 
-       if (down_interruptible(&saa7146_devices_lock))
+       if (mutex_lock_interruptible(&saa7146_devices_lock))
                return -ERESTARTSYS;
 
        if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
@@ -303,7 +301,7 @@ static int fops_release(struct inode *inode, struct file *file)
        file->private_data = NULL;
        kfree(fh);
 
-       up(&saa7146_devices_lock);
+       mutex_unlock(&saa7146_devices_lock);
 
        return 0;
 }
index 8aabdd8..d9953f7 100644 (file)
@@ -279,7 +279,7 @@ int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, in
        int address_err = 0;
        int short_delay = 0;
 
-       if (down_interruptible (&dev->i2c_lock))
+       if (mutex_lock_interruptible(&dev->i2c_lock))
                return -ERESTARTSYS;
 
        for(i=0;i<num;i++) {
@@ -366,7 +366,7 @@ out:
                }
        }
 
-       up(&dev->i2c_lock);
+       mutex_unlock(&dev->i2c_lock);
        return err;
 }
 
index 468d3c9..500bd3f 100644 (file)
@@ -410,7 +410,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
                            V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
                            sizeof(struct saa7146_buf),
                            file);
-       init_MUTEX(&fh->vbi_q.lock);
+       mutex_init(&fh->vbi_q.lock);
 
        init_timer(&fh->vbi_read_timeout);
        fh->vbi_read_timeout.function = vbi_read_timeout;
index 7ebac79..6b42713 100644 (file)
@@ -378,20 +378,20 @@ static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
                err = try_win(dev,&f->fmt.win);
                if (0 != err)
                        return err;
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
                fh->ov.win    = f->fmt.win;
                fh->ov.nclips = f->fmt.win.clipcount;
                if (fh->ov.nclips > 16)
                        fh->ov.nclips = 16;
                if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) {
-                       up(&dev->lock);
+                       mutex_unlock(&dev->lock);
                        return -EFAULT;
                }
 
                /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
                fh->ov.fh = fh;
 
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
 
                /* check if our current overlay is active */
                if (IS_OVERLAY_ACTIVE(fh) != 0) {
@@ -516,7 +516,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
                return -EINVAL;
        }
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
 
        switch (ctrl->type) {
        case V4L2_CTRL_TYPE_BOOLEAN:
@@ -560,7 +560,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
                /* fixme: we can support changing VFLIP and HFLIP here... */
                if (IS_CAPTURE_ACTIVE(fh) != 0) {
                        DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
-                       up(&dev->lock);
+                       mutex_unlock(&dev->lock);
                        return -EINVAL;
                }
                vv->hflip = c->value;
@@ -568,7 +568,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
        case V4L2_CID_VFLIP:
                if (IS_CAPTURE_ACTIVE(fh) != 0) {
                        DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
-                       up(&dev->lock);
+                       mutex_unlock(&dev->lock);
                        return -EINVAL;
                }
                vv->vflip = c->value;
@@ -577,7 +577,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
                return -EINVAL;
        }
        }
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 
        if (IS_OVERLAY_ACTIVE(fh) != 0) {
                saa7146_stop_preview(fh);
@@ -939,7 +939,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                        }
                }
 
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
 
                /* ok, accept it */
                vv->ov_fb = *fb;
@@ -948,7 +948,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                        vv->ov_fb.fmt.bytesperline =
                                vv->ov_fb.fmt.width*fmt->depth/8;
 
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
 
                return 0;
        }
@@ -1086,7 +1086,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                        }
                }
 
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
 
                for(i = 0; i < dev->ext_vv_data->num_stds; i++)
                        if (*id & dev->ext_vv_data->stds[i].id)
@@ -1098,7 +1098,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                        found = 1;
                }
 
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
 
                if (vv->ov_suspend != NULL) {
                        saa7146_start_preview(vv->ov_suspend);
@@ -1201,11 +1201,11 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                DEB_D(("VIDIOCGMBUF \n"));
 
                q = &fh->video_q;
-               down(&q->lock);
+               mutex_lock(&q->lock);
                err = videobuf_mmap_setup(q,gbuffers,gbufsize,
                                          V4L2_MEMORY_MMAP);
                if (err < 0) {
-                       up(&q->lock);
+                       mutex_unlock(&q->lock);
                        return err;
                }
                memset(mbuf,0,sizeof(*mbuf));
@@ -1213,7 +1213,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
                mbuf->size   = gbuffers * gbufsize;
                for (i = 0; i < gbuffers; i++)
                        mbuf->offsets[i] = i * gbufsize;
-               up(&q->lock);
+               mutex_unlock(&q->lock);
                return 0;
        }
        default:
@@ -1414,7 +1414,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
                            sizeof(struct saa7146_buf),
                            file);
 
-       init_MUTEX(&fh->video_q.lock);
+       mutex_init(&fh->video_q.lock);
 
        return 0;
 }
index 7d7e161..b3dd060 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/config.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
 
 #include "flexcop-reg.h"
 
@@ -73,8 +74,7 @@ struct flexcop_device {
        int (*fe_sleep) (struct dvb_frontend *);
 
        struct i2c_adapter i2c_adap;
-       struct semaphore i2c_sem;
-
+       struct mutex i2c_mutex;
        struct module *owner;
 
        /* options and status */
index 56495cb..e0bd2d8 100644 (file)
@@ -135,7 +135,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs
        struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
        int i, ret = 0;
 
-       if (down_interruptible(&fc->i2c_sem))
+       if (mutex_lock_interruptible(&fc->i2c_mutex))
                return -ERESTARTSYS;
 
        /* reading */
@@ -161,7 +161,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs
        else
                ret = num;
 
-       up(&fc->i2c_sem);
+       mutex_unlock(&fc->i2c_mutex);
 
        return ret;
 }
@@ -180,7 +180,7 @@ int flexcop_i2c_init(struct flexcop_device *fc)
 {
        int ret;
 
-       sema_init(&fc->i2c_sem,1);
+       mutex_init(&fc->i2c_mutex);
 
        memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
        strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
index d188e4c..9d197ef 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
index 356f447..5500f8a 100644 (file)
@@ -344,7 +344,7 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
        int retval;
 
        retval = 0;
-       if (down_interruptible (&bt->gpio_lock))
+       if (mutex_lock_interruptible(&bt->gpio_lock))
                return -ERESTARTSYS;
        /* special gpio signal */
        switch (cmd) {
@@ -375,7 +375,7 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
                retval = -EINVAL;
                break;
        }
-       up(&bt->gpio_lock);
+       mutex_unlock(&bt->gpio_lock);
        return retval;
 }
 
index 9faf937..f685bc1 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
+
 #include "bt848.h"
 #include "bttv.h"
 
@@ -108,7 +110,7 @@ struct cards {
 extern int bt878_num;
 
 struct bt878 {
-       struct semaphore  gpio_lock;
+       struct mutex gpio_lock;
        unsigned int nr;
        unsigned int bttv_nr;
        struct i2c_adapter *adapter;
index 0310e3d..1cfa5e5 100644 (file)
@@ -910,7 +910,7 @@ static int dst_get_device_id(struct dst_state *state)
 
 static int dst_probe(struct dst_state *state)
 {
-       sema_init(&state->dst_mutex, 1);
+       mutex_init(&state->dst_mutex);
        if ((rdc_8820_reset(state)) < 0) {
                dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
                return -1;
@@ -962,7 +962,7 @@ int dst_command(struct dst_state *state, u8 *data, u8 len)
 {
        u8 reply;
 
-       down(&state->dst_mutex);
+       mutex_lock(&state->dst_mutex);
        if ((dst_comm_init(state)) < 0) {
                dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
                goto error;
@@ -1013,11 +1013,11 @@ int dst_command(struct dst_state *state, u8 *data, u8 len)
                dprintk(verbose, DST_INFO, 1, "checksum failure");
                goto error;
        }
-       up(&state->dst_mutex);
+       mutex_unlock(&state->dst_mutex);
        return 0;
 
 error:
-       up(&state->dst_mutex);
+       mutex_unlock(&state->dst_mutex);
        return -EIO;
 
 }
@@ -1128,7 +1128,7 @@ static int dst_write_tuna(struct dvb_frontend *fe)
                        dst_set_voltage(fe, SEC_VOLTAGE_13);
        }
        state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-       down(&state->dst_mutex);
+       mutex_lock(&state->dst_mutex);
        if ((dst_comm_init(state)) < 0) {
                dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
                goto error;
@@ -1160,11 +1160,11 @@ static int dst_write_tuna(struct dvb_frontend *fe)
        state->diseq_flags |= ATTEMPT_TUNE;
        retval = dst_get_tuna(state);
 werr:
-       up(&state->dst_mutex);
+       mutex_unlock(&state->dst_mutex);
        return retval;
 
 error:
-       up(&state->dst_mutex);
+       mutex_unlock(&state->dst_mutex);
        return -EIO;
 }
 
index c650b4b..f6b49a8 100644 (file)
@@ -81,7 +81,7 @@ static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8
 {
        u8 reply;
 
-       down(&state->dst_mutex);
+       mutex_lock(&state->dst_mutex);
        dst_comm_init(state);
        msleep(65);
 
@@ -110,11 +110,11 @@ static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8
                        goto error;
                }
        }
-       up(&state->dst_mutex);
+       mutex_unlock(&state->dst_mutex);
        return 0;
 
 error:
-       up(&state->dst_mutex);
+       mutex_unlock(&state->dst_mutex);
        return -EIO;
 }
 
index 81557f3..51d4e04 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/dvb/frontend.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include "bt878.h"
 
 #include "dst_ca.h"
@@ -121,7 +122,7 @@ struct dst_state {
        u8 vendor[8];
        u8 board_info[8];
 
-       struct semaphore dst_mutex;
+       struct mutex dst_mutex;
 };
 
 struct dst_types {
index ea27b15..baa8227 100644 (file)
@@ -76,13 +76,13 @@ static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        if (!dvbdmx->dmx.frontend)
                return -EINVAL;
 
-       down(&card->lock);
+       mutex_lock(&card->lock);
        card->nfeeds++;
        rc = card->nfeeds;
        if (card->nfeeds == 1)
                bt878_start(card->bt, card->gpio_mode,
                            card->op_sync_orin, card->irq_err_ignore);
-       up(&card->lock);
+       mutex_unlock(&card->lock);
        return rc;
 }
 
@@ -96,11 +96,11 @@ static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        if (!dvbdmx->dmx.frontend)
                return -EINVAL;
 
-       down(&card->lock);
+       mutex_lock(&card->lock);
        card->nfeeds--;
        if (card->nfeeds == 0)
                bt878_stop(card->bt);
-       up(&card->lock);
+       mutex_unlock(&card->lock);
 
        return 0;
 }
@@ -239,6 +239,20 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
 
 static int pinnsat_pll_init(struct dvb_frontend* fe)
 {
+       struct dvb_bt8xx_card *card = fe->dvb->priv;
+
+       bttv_gpio_enable(card->bttv_nr, 1, 1);  /* output */
+       bttv_write_gpio(card->bttv_nr, 1, 1);   /* relay on */
+
+       return 0;
+}
+
+static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+{
+       struct dvb_bt8xx_card *card = fe->dvb->priv;
+
+       bttv_write_gpio(card->bttv_nr, 1, 0);   /* relay off */
+
        return 0;
 }
 
@@ -246,6 +260,7 @@ static struct cx24110_config pctvsat_config = {
        .demod_address = 0x55,
        .pll_init = pinnsat_pll_init,
        .pll_set = cx24108_pll_set,
+       .pll_sleep = pinnsat_pll_sleep,
 };
 
 static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -788,7 +803,7 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
        if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
                return -ENOMEM;
 
-       init_MUTEX(&card->lock);
+       mutex_init(&card->lock);
        card->bttv_nr = sub->core->nr;
        strncpy(card->card_name, sub->core->name, sizeof(sub->core->name));
        card->i2c_adapter = &sub->core->i2c_adap;
@@ -798,14 +813,14 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
                card->gpio_mode = 0x0400c060;
                /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
                              BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
-               card->op_sync_orin = 0;
-               card->irq_err_ignore = 0;
+               card->op_sync_orin = BT878_RISC_SYNC_MASK;
+               card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
                break;
 
        case BTTV_BOARD_DVICO_DVBT_LITE:
                card->gpio_mode = 0x0400C060;
-               card->op_sync_orin = 0;
-               card->irq_err_ignore = 0;
+               card->op_sync_orin = BT878_RISC_SYNC_MASK;
+               card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
                /* 26, 15, 14, 6, 5
                 * A_PWRDN  DA_DPM DA_SBR DA_IOM_DA
                 * DA_APP(parallel) */
@@ -820,15 +835,15 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
        case BTTV_BOARD_NEBULA_DIGITV:
        case BTTV_BOARD_AVDVBT_761:
                card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
-               card->op_sync_orin = 0;
-               card->irq_err_ignore = 0;
+               card->op_sync_orin = BT878_RISC_SYNC_MASK;
+               card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
                /* A_PWRDN DA_SBR DA_APP (high speed serial) */
                break;
 
        case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
                card->gpio_mode = 0x0400402B;
                card->op_sync_orin = BT878_RISC_SYNC_MASK;
-               card->irq_err_ignore = 0;
+               card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
                /* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
                break;
 
@@ -852,8 +867,8 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
 
        case BTTV_BOARD_PC_HDTV:
                card->gpio_mode = 0x0100EC7B;
-               card->op_sync_orin = 0;
-               card->irq_err_ignore = 0;
+               card->op_sync_orin = BT878_RISC_SYNC_MASK;
+               card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
                break;
 
        default:
@@ -881,7 +896,7 @@ static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
                return -EFAULT;
        }
 
-       init_MUTEX(&card->bt->gpio_lock);
+       mutex_init(&card->bt->gpio_lock);
        card->bt->bttv_nr = sub->core->nr;
 
        if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
index cf035a8..00dd9fa 100644 (file)
@@ -26,6 +26,7 @@
 #define DVB_BT8XX_H
 
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 #include "dvbdev.h"
 #include "dvb_net.h"
 #include "bttv.h"
@@ -38,7 +39,7 @@
 #include "lgdt330x.h"
 
 struct dvb_bt8xx_card {
-       struct semaphore lock;
+       struct mutex lock;
        int nfeeds;
        char card_name[32];
        struct dvb_adapter dvb_adapter;
index c4b4c5b..71b575d 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/dvb/frontend.h>
+#include <linux/mutex.h>
 
 #include "dmxdev.h"
 #include "dvb_demux.h"
@@ -116,7 +117,7 @@ static struct dvb_frontend_info cinergyt2_fe_info = {
 struct cinergyt2 {
        struct dvb_demux demux;
        struct usb_device *udev;
-       struct semaphore sem;
+       struct mutex sem;
        struct dvb_adapter adapter;
        struct dvb_device *fedev;
        struct dmxdev dmxdev;
@@ -345,14 +346,14 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct cinergyt2 *cinergyt2 = demux->priv;
 
-       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (cinergyt2->streaming == 0)
                cinergyt2_start_stream_xfer(cinergyt2);
 
        cinergyt2->streaming++;
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
        return 0;
 }
 
@@ -361,13 +362,13 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct cinergyt2 *cinergyt2 = demux->priv;
 
-       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (--cinergyt2->streaming == 0)
                cinergyt2_stop_stream_xfer(cinergyt2);
 
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
        return 0;
 }
 
@@ -483,11 +484,11 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
        int err = -ERESTARTSYS;
 
-       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if ((err = dvb_generic_open(inode, file))) {
-               up(&cinergyt2->sem);
+               mutex_unlock(&cinergyt2->sem);
                return err;
        }
 
@@ -499,12 +500,15 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
 
        atomic_inc(&cinergyt2->inuse);
 
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
        return 0;
 }
 
 static void cinergyt2_unregister(struct cinergyt2 *cinergyt2)
 {
+       dvb_net_release(&cinergyt2->dvbnet);
+       dvb_dmxdev_release(&cinergyt2->dmxdev);
+       dvb_dmx_release(&cinergyt2->demux);
        dvb_unregister_device(cinergyt2->fedev);
        dvb_unregister_adapter(&cinergyt2->adapter);
 
@@ -517,7 +521,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
        struct dvb_device *dvbdev = file->private_data;
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
 
-       if (down_interruptible(&cinergyt2->sem))
+       if (mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) {
@@ -526,7 +530,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
                cinergyt2_sleep(cinergyt2, 1);
        }
 
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
 
        if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) {
                warn("delayed unregister in release");
@@ -541,12 +545,12 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
        struct dvb_device *dvbdev = file->private_data;
        struct cinergyt2 *cinergyt2 = dvbdev->priv;
 
-       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        poll_wait(file, &cinergyt2->poll_wq, wait);
 
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
 
        return (POLLIN | POLLRDNORM | POLLPRI);
 }
@@ -613,7 +617,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
                if (copy_from_user(&p, (void  __user*) arg, sizeof(p)))
                        return -EFAULT;
 
-               if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+               if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                        return -ERESTARTSYS;
 
                param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -629,7 +633,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
                                        (char *) param, sizeof(*param),
                                        NULL, 0);
 
-               up(&cinergyt2->sem);
+               mutex_unlock(&cinergyt2->sem);
 
                return (err < 0) ? err : 0;
        }
@@ -724,7 +728,7 @@ static void cinergyt2_query_rc (void *data)
        struct cinergyt2_rc_event rc_events[12];
        int n, len, i;
 
-       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return;
 
        len = cinergyt2_command(cinergyt2, buf, sizeof(buf),
@@ -784,7 +788,7 @@ out:
        schedule_delayed_work(&cinergyt2->rc_query_work,
                              msecs_to_jiffies(RC_QUERY_INTERVAL));
 
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
 }
 
 static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
@@ -849,7 +853,7 @@ static void cinergyt2_query (void *data)
        uint8_t lock_bits;
        uint32_t unc;
 
-       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return;
 
        unc = s->uncorrected_block_count;
@@ -868,7 +872,7 @@ static void cinergyt2_query (void *data)
        schedule_delayed_work(&cinergyt2->query_work,
                              msecs_to_jiffies(QUERY_INTERVAL));
 
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
 }
 
 static int cinergyt2_probe (struct usb_interface *intf,
@@ -885,7 +889,7 @@ static int cinergyt2_probe (struct usb_interface *intf,
        memset (cinergyt2, 0, sizeof (struct cinergyt2));
        usb_set_intfdata (intf, (void *) cinergyt2);
 
-       init_MUTEX(&cinergyt2->sem);
+       mutex_init(&cinergyt2->sem);
        init_waitqueue_head (&cinergyt2->poll_wq);
        INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2);
 
@@ -937,6 +941,7 @@ static int cinergyt2_probe (struct usb_interface *intf,
        return 0;
 
 bailout:
+       dvb_net_release(&cinergyt2->dvbnet);
        dvb_dmxdev_release(&cinergyt2->dmxdev);
        dvb_dmx_release(&cinergyt2->demux);
        dvb_unregister_adapter(&cinergyt2->adapter);
@@ -967,7 +972,7 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
 {
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 
-       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (state.event > PM_EVENT_ON) {
@@ -981,7 +986,7 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
                cinergyt2_sleep(cinergyt2, 1);
        }
 
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
        return 0;
 }
 
@@ -990,7 +995,7 @@ static int cinergyt2_resume (struct usb_interface *intf)
        struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
        struct dvbt_set_parameters_msg *param = &cinergyt2->param;
 
-       if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem))
+       if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
                return -ERESTARTSYS;
 
        if (!cinergyt2->sleeping) {
@@ -1003,7 +1008,7 @@ static int cinergyt2_resume (struct usb_interface *intf)
 
        cinergyt2_resume_rc(cinergyt2);
 
-       up(&cinergyt2->sem);
+       mutex_unlock(&cinergyt2->sem);
        return 0;
 }
 
index 7b8373a..09e96e9 100644 (file)
@@ -1,9 +1,8 @@
 /*
  * dmxdev.c - DVB demultiplexer device
  *
- * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
- *               & Marcus Metzler <marcus@convergence.de>
-                     for convergence integrated media GmbH
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ *                   for convergence integrated media GmbH
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -32,7 +31,6 @@
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-
 #include "dmxdev.h"
 
 static int debug;
@@ -42,177 +40,133 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
 #define dprintk        if (debug) printk
 
-static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
+static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
+                                  const u8 *src, size_t len)
 {
-       buffer->data=NULL;
-       buffer->size=8192;
-       buffer->pread=0;
-       buffer->pwrite=0;
-       buffer->error=0;
-       init_waitqueue_head(&buffer->queue);
-}
-
-static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len)
-{
-       int split;
-       int free;
-       int todo;
+       ssize_t free;
 
        if (!len)
                return 0;
        if (!buf->data)
                return 0;
 
-       free=buf->pread-buf->pwrite;
-       split=0;
-       if (free<=0) {
-               free+=buf->size;
-               split=buf->size-buf->pwrite;
-       }
-       if (len>=free) {
+       free = dvb_ringbuffer_free(buf);
+       if (len > free) {
                dprintk("dmxdev: buffer overflow\n");
-               return -1;
+               return -EOVERFLOW;
        }
-       if (split>=len)
-               split=0;
-       todo=len;
-       if (split) {
-               memcpy(buf->data + buf->pwrite, src, split);
-               todo-=split;
-               buf->pwrite=0;
-       }
-       memcpy(buf->data + buf->pwrite, src+split, todo);
-       buf->pwrite=(buf->pwrite+todo)%buf->size;
-       return len;
+
+       return dvb_ringbuffer_write(buf, src, len);
 }
 
-static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src,
-               int non_blocking, char __user *buf, size_t count, loff_t *ppos)
+static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+                                     int non_blocking, char __user *buf,
+                                     size_t count, loff_t *ppos)
 {
-       unsigned long todo=count;
-       int split, avail, error;
+       size_t todo;
+       ssize_t avail;
+       ssize_t ret = 0;
 
        if (!src->data)
                return 0;
 
-       if ((error=src->error)) {
-               src->pwrite=src->pread;
-               src->error=0;
-               return error;
+       if (src->error) {
+               ret = src->error;
+               dvb_ringbuffer_flush(src);
+               return ret;
        }
 
-       if (non_blocking && (src->pwrite==src->pread))
-               return -EWOULDBLOCK;
-
-       while (todo>0) {
-               if (non_blocking && (src->pwrite==src->pread))
-                       return (count-todo) ? (count-todo) : -EWOULDBLOCK;
+       for (todo = count; todo > 0; todo -= ret) {
+               if (non_blocking && dvb_ringbuffer_empty(src)) {
+                       ret = -EWOULDBLOCK;
+                       break;
+               }
 
-               if (wait_event_interruptible(src->queue,
-                                            (src->pread!=src->pwrite) ||
-                                            (src->error))<0)
-                       return count-todo;
+               ret = wait_event_interruptible(src->queue,
+                                              !dvb_ringbuffer_empty(src) ||
+                                              (src->error != 0));
+               if (ret < 0)
+                       break;
 
-               if ((error=src->error)) {
-                       src->pwrite=src->pread;
-                       src->error=0;
-                       return error;
+               if (src->error) {
+                       ret = src->error;
+                       dvb_ringbuffer_flush(src);
+                       break;
                }
 
-               split=src->size;
-               avail=src->pwrite - src->pread;
-               if (avail<0) {
-                       avail+=src->size;
-                       split=src->size - src->pread;
-               }
-               if (avail>todo)
-                       avail=todo;
-               if (split<avail) {
-                       if (copy_to_user(buf, src->data+src->pread, split))
-                                 return -EFAULT;
-                       buf+=split;
-                       src->pread=0;
-                       todo-=split;
-                       avail-=split;
-               }
-               if (avail) {
-                       if (copy_to_user(buf, src->data+src->pread, avail))
-                               return -EFAULT;
-                       src->pread = (src->pread + avail) % src->size;
-                       todo-=avail;
-                       buf+=avail;
-               }
+               avail = dvb_ringbuffer_avail(src);
+               if (avail > todo)
+                       avail = todo;
+
+               ret = dvb_ringbuffer_read(src, buf, avail, 1);
+               if (ret < 0)
+                       break;
+
+               buf += ret;
        }
-       return count;
+
+       return (count - todo) ? (count - todo) : ret;
 }
 
-static struct dmx_frontend * get_fe(struct dmx_demux *demux, int type)
+static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
 {
        struct list_head *head, *pos;
 
-       head=demux->get_frontends(demux);
+       head = demux->get_frontends(demux);
        if (!head)
                return NULL;
        list_for_each(pos, head)
-               if (DMX_FE_ENTRY(pos)->source==type)
+               if (DMX_FE_ENTRY(pos)->source == type)
                        return DMX_FE_ENTRY(pos);
 
        return NULL;
 }
 
-static inline void dvb_dmxdev_dvr_state_set(struct dmxdev_dvr *dmxdevdvr, int state)
-{
-       spin_lock_irq(&dmxdevdvr->dev->lock);
-       dmxdevdvr->state=state;
-       spin_unlock_irq(&dmxdevdvr->dev->lock);
-}
-
 static int dvb_dvr_open(struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
        struct dmx_frontend *front;
 
-       dprintk ("function : %s\n", __FUNCTION__);
+       dprintk("function : %s\n", __FUNCTION__);
 
-       if (down_interruptible (&dmxdev->mutex))
+       if (mutex_lock_interruptible(&dmxdev->mutex))
                return -ERESTARTSYS;
 
-       if ((file->f_flags&O_ACCMODE)==O_RDWR) {
-               if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) {
-                       up(&dmxdev->mutex);
+       if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+               if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
+                       mutex_unlock(&dmxdev->mutex);
                        return -EOPNOTSUPP;
                }
        }
 
-       if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
-             dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
-             dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE;
-             dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE);
-             if (!dmxdev->dvr_buffer.data) {
-                     up(&dmxdev->mutex);
-                     return -ENOMEM;
-             }
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+               void *mem = vmalloc(DVR_BUFFER_SIZE);
+               if (!mem) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ENOMEM;
+               }
+               dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
        }
 
-       if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
-               dmxdev->dvr_orig_fe=dmxdev->demux->frontend;
+       if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+               dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
 
                if (!dmxdev->demux->write) {
-                       up(&dmxdev->mutex);
+                       mutex_unlock(&dmxdev->mutex);
                        return -EOPNOTSUPP;
                }
 
-               front=get_fe(dmxdev->demux, DMX_MEMORY_FE);
+               front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
 
                if (!front) {
-                       up(&dmxdev->mutex);
+                       mutex_unlock(&dmxdev->mutex);
                        return -EINVAL;
                }
                dmxdev->demux->disconnect_frontend(dmxdev->demux);
                dmxdev->demux->connect_frontend(dmxdev->demux, front);
        }
-       up(&dmxdev->mutex);
+       mutex_unlock(&dmxdev->mutex);
        return 0;
 }
 
@@ -221,30 +175,30 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
 
-       if (down_interruptible (&dmxdev->mutex))
+       if (mutex_lock_interruptible(&dmxdev->mutex))
                return -ERESTARTSYS;
 
-       if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
+       if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
                dmxdev->demux->disconnect_frontend(dmxdev->demux);
                dmxdev->demux->connect_frontend(dmxdev->demux,
                                                dmxdev->dvr_orig_fe);
        }
-       if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
                if (dmxdev->dvr_buffer.data) {
-                       void *mem=dmxdev->dvr_buffer.data;
+                       void *mem = dmxdev->dvr_buffer.data;
                        mb();
                        spin_lock_irq(&dmxdev->lock);
-                       dmxdev->dvr_buffer.data=NULL;
+                       dmxdev->dvr_buffer.data = NULL;
                        spin_unlock_irq(&dmxdev->lock);
                        vfree(mem);
                }
        }
-       up(&dmxdev->mutex);
+       mutex_unlock(&dmxdev->mutex);
        return 0;
 }
 
 static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
-               size_t count, loff_t *ppos)
+                            size_t count, loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
@@ -252,60 +206,62 @@ static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
 
        if (!dmxdev->demux->write)
                return -EOPNOTSUPP;
-       if ((file->f_flags&O_ACCMODE)!=O_WRONLY)
+       if ((file->f_flags & O_ACCMODE) != O_WRONLY)
                return -EINVAL;
-       if (down_interruptible (&dmxdev->mutex))
+       if (mutex_lock_interruptible(&dmxdev->mutex))
                return -ERESTARTSYS;
-       ret=dmxdev->demux->write(dmxdev->demux, buf, count);
-       up(&dmxdev->mutex);
+       ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+       mutex_unlock(&dmxdev->mutex);
        return ret;
 }
 
 static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
-               loff_t *ppos)
+                           loff_t *ppos)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
        int ret;
 
-       //down(&dmxdev->mutex);
-       ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-                             file->f_flags&O_NONBLOCK,
-                             buf, count, ppos);
-       //up(&dmxdev->mutex);
+       //mutex_lock(&dmxdev->mutex);
+       ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+                                    file->f_flags & O_NONBLOCK,
+                                    buf, count, ppos);
+       //mutex_unlock(&dmxdev->mutex);
        return ret;
 }
 
-static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter *dmxdevfilter, int state)
+static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
+                                              *dmxdevfilter, int state)
 {
        spin_lock_irq(&dmxdevfilter->dev->lock);
-       dmxdevfilter->state=state;
+       dmxdevfilter->state = state;
        spin_unlock_irq(&dmxdevfilter->dev->lock);
 }
 
-static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsigned long size)
+static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
+                                     unsigned long size)
 {
-       struct dmxdev_buffer *buf=&dmxdevfilter->buffer;
+       struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
        void *mem;
 
-       if (buf->size==size)
+       if (buf->size == size)
                return 0;
-       if (dmxdevfilter->state>=DMXDEV_STATE_GO)
+       if (dmxdevfilter->state >= DMXDEV_STATE_GO)
                return -EBUSY;
        spin_lock_irq(&dmxdevfilter->dev->lock);
-       mem=buf->data;
-       buf->data=NULL;
-       buf->size=size;
-       buf->pwrite=buf->pread=0;
+       mem = buf->data;
+       buf->data = NULL;
+       buf->size = size;
+       dvb_ringbuffer_flush(buf);
        spin_unlock_irq(&dmxdevfilter->dev->lock);
        vfree(mem);
 
        if (buf->size) {
-               mem=vmalloc(dmxdevfilter->buffer.size);
+               mem = vmalloc(dmxdevfilter->buffer.size);
                if (!mem)
                        return -ENOMEM;
                spin_lock_irq(&dmxdevfilter->dev->lock);
-               buf->data=mem;
+               buf->data = mem;
                spin_unlock_irq(&dmxdevfilter->dev->lock);
        }
        return 0;
@@ -313,31 +269,33 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsign
 
 static void dvb_dmxdev_filter_timeout(unsigned long data)
 {
-       struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *)data;
+       struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
 
-       dmxdevfilter->buffer.error=-ETIMEDOUT;
+       dmxdevfilter->buffer.error = -ETIMEDOUT;
        spin_lock_irq(&dmxdevfilter->dev->lock);
-       dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT;
+       dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
        spin_unlock_irq(&dmxdevfilter->dev->lock);
        wake_up(&dmxdevfilter->buffer.queue);
 }
 
 static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
 {
-       struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec;
+       struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
 
        del_timer(&dmxdevfilter->timer);
        if (para->timeout) {
-               dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout;
-               dmxdevfilter->timer.data=(unsigned long) dmxdevfilter;
-               dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000;
+               dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
+               dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
+               dmxdevfilter->timer.expires =
+                   jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
                add_timer(&dmxdevfilter->timer);
        }
 }
 
 static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
-                           const u8 *buffer2, size_t buffer2_len,
-                           struct dmx_section_filter *filter, enum dmx_success success)
+                                      const u8 *buffer2, size_t buffer2_len,
+                                      struct dmx_section_filter *filter,
+                                      enum dmx_success success)
 {
        struct dmxdev_filter *dmxdevfilter = filter->priv;
        int ret;
@@ -347,68 +305,68 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
                return 0;
        }
        spin_lock(&dmxdevfilter->dev->lock);
-       if (dmxdevfilter->state!=DMXDEV_STATE_GO) {
+       if (dmxdevfilter->state != DMXDEV_STATE_GO) {
                spin_unlock(&dmxdevfilter->dev->lock);
                return 0;
        }
        del_timer(&dmxdevfilter->timer);
        dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
                buffer1[0], buffer1[1],
-               buffer1[2], buffer1[3],
-               buffer1[4], buffer1[5]);
-       ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len);
-       if (ret==buffer1_len) {
-               ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len);
+               buffer1[2], buffer1[3], buffer1[4], buffer1[5]);
+       ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
+                                     buffer1_len);
+       if (ret == buffer1_len) {
+               ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
+                                             buffer2_len);
        }
-       if (ret<0) {
-               dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread;
-               dmxdevfilter->buffer.error=-EOVERFLOW;
+       if (ret < 0) {
+               dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+               dmxdevfilter->buffer.error = ret;
        }
-       if (dmxdevfilter->params.sec.flags&DMX_ONESHOT)
-               dmxdevfilter->state=DMXDEV_STATE_DONE;
+       if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
+               dmxdevfilter->state = DMXDEV_STATE_DONE;
        spin_unlock(&dmxdevfilter->dev->lock);
        wake_up(&dmxdevfilter->buffer.queue);
        return 0;
 }
 
 static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
-                      const u8 *buffer2, size_t buffer2_len,
-                      struct dmx_ts_feed *feed, enum dmx_success success)
+                                 const u8 *buffer2, size_t buffer2_len,
+                                 struct dmx_ts_feed *feed,
+                                 enum dmx_success success)
 {
        struct dmxdev_filter *dmxdevfilter = feed->priv;
-       struct dmxdev_buffer *buffer;
+       struct dvb_ringbuffer *buffer;
        int ret;
 
        spin_lock(&dmxdevfilter->dev->lock);
-       if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) {
+       if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
                spin_unlock(&dmxdevfilter->dev->lock);
                return 0;
        }
 
-       if (dmxdevfilter->params.pes.output==DMX_OUT_TAP)
-               buffer=&dmxdevfilter->buffer;
+       if (dmxdevfilter->params.pes.output == DMX_OUT_TAP)
+               buffer = &dmxdevfilter->buffer;
        else
-               buffer=&dmxdevfilter->dev->dvr_buffer;
+               buffer = &dmxdevfilter->dev->dvr_buffer;
        if (buffer->error) {
                spin_unlock(&dmxdevfilter->dev->lock);
                wake_up(&buffer->queue);
                return 0;
        }
-       ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
-       if (ret==buffer1_len)
-               ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
-       if (ret<0) {
-               buffer->pwrite=buffer->pread;
-               buffer->error=-EOVERFLOW;
+       ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
+       if (ret == buffer1_len)
+               ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
+       if (ret < 0) {
+               dvb_ringbuffer_flush(buffer);
+               buffer->error = ret;
        }
        spin_unlock(&dmxdevfilter->dev->lock);
        wake_up(&buffer->queue);
        return 0;
 }
 
-
 /* stop feed but only mark the specified filter as stopped (state set) */
-
 static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
 {
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
@@ -427,20 +385,16 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
        return 0;
 }
 
-
 /* start feed associated with the specified filter */
-
 static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
 {
-       dvb_dmxdev_filter_state_set (filter, DMXDEV_STATE_GO);
+       dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
 
        switch (filter->type) {
        case DMXDEV_TYPE_SEC:
                return filter->feed.sec->start_filtering(filter->feed.sec);
-               break;
        case DMXDEV_TYPE_PES:
                return filter->feed.ts->start_filtering(filter->feed.ts);
-               break;
        default:
                return -EINVAL;
        }
@@ -448,32 +402,31 @@ static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
        return 0;
 }
 
-
 /* restart section feed if it has filters left associated with it,
    otherwise release the feed */
-
 static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
 {
        int i;
        struct dmxdev *dmxdev = filter->dev;
        u16 pid = filter->params.sec.pid;
 
-       for (i=0; i<dmxdev->filternum; i++)
-               if (dmxdev->filter[i].state>=DMXDEV_STATE_GO &&
-                   dmxdev->filter[i].type==DMXDEV_TYPE_SEC &&
-                   dmxdev->filter[i].pid==pid) {
+       for (i = 0; i < dmxdev->filternum; i++)
+               if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+                   dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+                   dmxdev->filter[i].params.sec.pid == pid) {
                        dvb_dmxdev_feed_start(&dmxdev->filter[i]);
                        return 0;
                }
 
-       filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec);
+       filter->dev->demux->release_section_feed(dmxdev->demux,
+                                                filter->feed.sec);
 
        return 0;
 }
 
 static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
 {
-       if (dmxdevfilter->state<DMXDEV_STATE_GO)
+       if (dmxdevfilter->state < DMXDEV_STATE_GO)
                return 0;
 
        switch (dmxdevfilter->type) {
@@ -483,36 +436,36 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
                dvb_dmxdev_feed_stop(dmxdevfilter);
                if (dmxdevfilter->filter.sec)
                        dmxdevfilter->feed.sec->
-                               release_filter(dmxdevfilter->feed.sec,
-                                              dmxdevfilter->filter.sec);
+                           release_filter(dmxdevfilter->feed.sec,
+                                          dmxdevfilter->filter.sec);
                dvb_dmxdev_feed_restart(dmxdevfilter);
-               dmxdevfilter->feed.sec=NULL;
+               dmxdevfilter->feed.sec = NULL;
                break;
        case DMXDEV_TYPE_PES:
                if (!dmxdevfilter->feed.ts)
                        break;
                dvb_dmxdev_feed_stop(dmxdevfilter);
                dmxdevfilter->dev->demux->
-                       release_ts_feed(dmxdevfilter->dev->demux,
-                                       dmxdevfilter->feed.ts);
-               dmxdevfilter->feed.ts=NULL;
+                   release_ts_feed(dmxdevfilter->dev->demux,
+                                   dmxdevfilter->feed.ts);
+               dmxdevfilter->feed.ts = NULL;
                break;
        default:
-               if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED)
+               if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
                        return 0;
                return -EINVAL;
        }
-       dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0;
+
+       dvb_ringbuffer_flush(&dmxdevfilter->buffer);
        return 0;
 }
 
 static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
 {
-       if (dmxdevfilter->state<DMXDEV_STATE_SET)
+       if (dmxdevfilter->state < DMXDEV_STATE_SET)
                return 0;
 
-       dmxdevfilter->type=DMXDEV_TYPE_NONE;
-       dmxdevfilter->pid=0xffff;
+       dmxdevfilter->type = DMXDEV_TYPE_NONE;
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
        return 0;
 }
@@ -529,32 +482,33 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
        if (filter->state >= DMXDEV_STATE_GO)
                dvb_dmxdev_filter_stop(filter);
 
-       if (!(mem = filter->buffer.data)) {
+       if (!filter->buffer.data) {
                mem = vmalloc(filter->buffer.size);
+               if (!mem)
+                       return -ENOMEM;
                spin_lock_irq(&filter->dev->lock);
-               filter->buffer.data=mem;
+               filter->buffer.data = mem;
                spin_unlock_irq(&filter->dev->lock);
-               if (!filter->buffer.data)
-                       return -ENOMEM;
        }
 
-       filter->buffer.pwrite = filter->buffer.pread = 0;
+       dvb_ringbuffer_flush(&filter->buffer);
 
        switch (filter->type) {
        case DMXDEV_TYPE_SEC:
        {
-               struct dmx_sct_filter_params *para=&filter->params.sec;
-               struct dmx_section_filter **secfilter=&filter->filter.sec;
-               struct dmx_section_feed **secfeed=&filter->feed.sec;
+               struct dmx_sct_filter_params *para = &filter->params.sec;
+               struct dmx_section_filter **secfilter = &filter->filter.sec;
+               struct dmx_section_feed **secfeed = &filter->feed.sec;
+
+               *secfilter = NULL;
+               *secfeed = NULL;
 
-               *secfilter=NULL;
-               *secfeed=NULL;
 
                /* find active filter/feed with same PID */
-               for (i=0; i<dmxdev->filternum; i++) {
+               for (i = 0; i < dmxdev->filternum; i++) {
                        if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
-                           dmxdev->filter[i].pid == para->pid &&
-                           dmxdev->filter[i].type == DMXDEV_TYPE_SEC) {
+                           dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+                           dmxdev->filter[i].params.sec.pid == para->pid) {
                                *secfeed = dmxdev->filter[i].feed.sec;
                                break;
                        }
@@ -562,21 +516,20 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
 
                /* if no feed found, try to allocate new one */
                if (!*secfeed) {
-                       ret=dmxdev->demux->allocate_section_feed(dmxdev->demux,
-                                                                secfeed,
-                                                  dvb_dmxdev_section_callback);
-                       if (ret<0) {
-                               printk ("DVB (%s): could not alloc feed\n",
-                                       __FUNCTION__);
+                       ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
+                                                                  secfeed,
+                                                                  dvb_dmxdev_section_callback);
+                       if (ret < 0) {
+                               printk("DVB (%s): could not alloc feed\n",
+                                      __FUNCTION__);
                                return ret;
                        }
 
-                       ret=(*secfeed)->set(*secfeed, para->pid, 32768,
-                                           (para->flags & DMX_CHECK_CRC) ? 1 : 0);
-
-                       if (ret<0) {
-                               printk ("DVB (%s): could not set feed\n",
-                                       __FUNCTION__);
+                       ret = (*secfeed)->set(*secfeed, para->pid, 32768,
+                                             (para->flags & DMX_CHECK_CRC) ? 1 : 0);
+                       if (ret < 0) {
+                               printk("DVB (%s): could not set feed\n",
+                                      __FUNCTION__);
                                dvb_dmxdev_feed_restart(filter);
                                return ret;
                        }
@@ -584,41 +537,38 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
                        dvb_dmxdev_feed_stop(filter);
                }
 
-               ret=(*secfeed)->allocate_filter(*secfeed, secfilter);
-
+               ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
                if (ret < 0) {
                        dvb_dmxdev_feed_restart(filter);
                        filter->feed.sec->start_filtering(*secfeed);
-                       dprintk ("could not get filter\n");
+                       dprintk("could not get filter\n");
                        return ret;
                }
 
                (*secfilter)->priv = filter;
 
                memcpy(&((*secfilter)->filter_value[3]),
-                      &(para->filter.filter[1]), DMX_FILTER_SIZE-1);
+                      &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
                memcpy(&(*secfilter)->filter_mask[3],
-                      &para->filter.mask[1], DMX_FILTER_SIZE-1);
+                      &para->filter.mask[1], DMX_FILTER_SIZE - 1);
                memcpy(&(*secfilter)->filter_mode[3],
-                      &para->filter.mode[1], DMX_FILTER_SIZE-1);
+                      &para->filter.mode[1], DMX_FILTER_SIZE - 1);
 
-               (*secfilter)->filter_value[0]=para->filter.filter[0];
-               (*secfilter)->filter_mask[0]=para->filter.mask[0];
-               (*secfilter)->filter_mode[0]=para->filter.mode[0];
-               (*secfilter)->filter_mask[1]=0;
-               (*secfilter)->filter_mask[2]=0;
+               (*secfilter)->filter_value[0] = para->filter.filter[0];
+               (*secfilter)->filter_mask[0] = para->filter.mask[0];
+               (*secfilter)->filter_mode[0] = para->filter.mode[0];
+               (*secfilter)->filter_mask[1] = 0;
+               (*secfilter)->filter_mask[2] = 0;
 
                filter->todo = 0;
 
-               ret = filter->feed.sec->start_filtering (filter->feed.sec);
-
+               ret = filter->feed.sec->start_filtering(filter->feed.sec);
                if (ret < 0)
                        return ret;
 
                dvb_dmxdev_filter_timer(filter);
                break;
        }
-
        case DMXDEV_TYPE_PES:
        {
                struct timespec timeout = { 0 };
@@ -630,41 +580,41 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
                struct dmx_ts_feed **tsfeed = &filter->feed.ts;
 
                filter->feed.ts = NULL;
-               otype=para->output;
+               otype = para->output;
 
-               ts_pes=(enum dmx_ts_pes) para->pes_type;
+               ts_pes = (enum dmx_ts_pes)para->pes_type;
 
-               if (ts_pes<DMX_PES_OTHER)
-                       ts_type=TS_DECODER;
+               if (ts_pes < DMX_PES_OTHER)
+                       ts_type = TS_DECODER;
                else
-                       ts_type=0;
+                       ts_type = 0;
 
                if (otype == DMX_OUT_TS_TAP)
                        ts_type |= TS_PACKET;
 
                if (otype == DMX_OUT_TAP)
-                       ts_type |= TS_PAYLOAD_ONLY|TS_PACKET;
+                       ts_type |= TS_PAYLOAD_ONLY | TS_PACKET;
 
-               ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux,
-                                                   tsfeed,
-                                                   dvb_dmxdev_ts_callback);
-               if (ret<0)
+               ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
+                                                     tsfeed,
+                                                     dvb_dmxdev_ts_callback);
+               if (ret < 0)
                        return ret;
 
-               (*tsfeed)->priv = (void *) filter;
+               (*tsfeed)->priv = filter;
 
                ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
                                     32768, timeout);
-
                if (ret < 0) {
-                       dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
+                       dmxdev->demux->release_ts_feed(dmxdev->demux,
+                                                      *tsfeed);
                        return ret;
                }
 
                ret = filter->feed.ts->start_filtering(filter->feed.ts);
-
                if (ret < 0) {
-                       dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
+                       dmxdev->demux->release_ts_feed(dmxdev->demux,
+                                                      *tsfeed);
                        return ret;
                }
 
@@ -688,41 +638,40 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
        if (!dmxdev->filter)
                return -EINVAL;
 
-       if (down_interruptible(&dmxdev->mutex))
+       if (mutex_lock_interruptible(&dmxdev->mutex))
                return -ERESTARTSYS;
 
-       for (i=0; i<dmxdev->filternum; i++)
-               if (dmxdev->filter[i].state==DMXDEV_STATE_FREE)
+       for (i = 0; i < dmxdev->filternum; i++)
+               if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
                        break;
 
-       if (i==dmxdev->filternum) {
-               up(&dmxdev->mutex);
+       if (i == dmxdev->filternum) {
+               mutex_unlock(&dmxdev->mutex);
                return -EMFILE;
        }
 
-       dmxdevfilter=&dmxdev->filter[i];
-       sema_init(&dmxdevfilter->mutex, 1);
-       dmxdevfilter->dvbdev=dmxdev->dvbdev;
-       file->private_data=dmxdevfilter;
+       dmxdevfilter = &dmxdev->filter[i];
+       mutex_init(&dmxdevfilter->mutex);
+       file->private_data = dmxdevfilter;
 
-       dvb_dmxdev_buffer_init(&dmxdevfilter->buffer);
-       dmxdevfilter->type=DMXDEV_TYPE_NONE;
+       dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
+       dmxdevfilter->type = DMXDEV_TYPE_NONE;
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
-       dmxdevfilter->feed.ts=NULL;
+       dmxdevfilter->feed.ts = NULL;
        init_timer(&dmxdevfilter->timer);
 
-       up(&dmxdev->mutex);
+       mutex_unlock(&dmxdev->mutex);
        return 0;
 }
 
-
-static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter)
+static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
+                                 struct dmxdev_filter *dmxdevfilter)
 {
-       if (down_interruptible(&dmxdev->mutex))
+       if (mutex_lock_interruptible(&dmxdev->mutex))
                return -ERESTARTSYS;
 
-       if (down_interruptible(&dmxdevfilter->mutex)) {
-               up(&dmxdev->mutex);
+       if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+               mutex_unlock(&dmxdev->mutex);
                return -ERESTARTSYS;
        }
 
@@ -730,18 +679,18 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *d
        dvb_dmxdev_filter_reset(dmxdevfilter);
 
        if (dmxdevfilter->buffer.data) {
-               void *mem=dmxdevfilter->buffer.data;
+               void *mem = dmxdevfilter->buffer.data;
 
                spin_lock_irq(&dmxdev->lock);
-               dmxdevfilter->buffer.data=NULL;
+               dmxdevfilter->buffer.data = NULL;
                spin_unlock_irq(&dmxdev->lock);
                vfree(mem);
        }
 
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
        wake_up(&dmxdevfilter->buffer.queue);
-       up(&dmxdevfilter->mutex);
-       up(&dmxdev->mutex);
+       mutex_unlock(&dmxdevfilter->mutex);
+       mutex_unlock(&dmxdev->mutex);
        return 0;
 }
 
@@ -749,173 +698,171 @@ static inline void invert_mode(dmx_filter_t *filter)
 {
        int i;
 
-       for (i=0; i<DMX_FILTER_SIZE; i++)
-               filter->mode[i]^=0xff;
+       for (i = 0; i < DMX_FILTER_SIZE; i++)
+               filter->mode[i] ^= 0xff;
 }
 
-
 static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
-               struct dmxdev_filter *dmxdevfilter,
-               struct dmx_sct_filter_params *params)
+                                struct dmxdev_filter *dmxdevfilter,
+                                struct dmx_sct_filter_params *params)
 {
-       dprintk ("function : %s\n", __FUNCTION__);
+       dprintk("function : %s\n", __FUNCTION__);
 
        dvb_dmxdev_filter_stop(dmxdevfilter);
 
-       dmxdevfilter->type=DMXDEV_TYPE_SEC;
-       dmxdevfilter->pid=params->pid;
+       dmxdevfilter->type = DMXDEV_TYPE_SEC;
        memcpy(&dmxdevfilter->params.sec,
               params, sizeof(struct dmx_sct_filter_params));
        invert_mode(&dmxdevfilter->params.sec.filter);
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
 
-       if (params->flags&DMX_IMMEDIATE_START)
+       if (params->flags & DMX_IMMEDIATE_START)
                return dvb_dmxdev_filter_start(dmxdevfilter);
 
        return 0;
 }
 
 static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
-                  struct dmxdev_filter *dmxdevfilter,
-                  struct dmx_pes_filter_params *params)
+                                    struct dmxdev_filter *dmxdevfilter,
+                                    struct dmx_pes_filter_params *params)
 {
        dvb_dmxdev_filter_stop(dmxdevfilter);
 
-       if (params->pes_type>DMX_PES_OTHER || params->pes_type<0)
+       if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
                return -EINVAL;
 
-       dmxdevfilter->type=DMXDEV_TYPE_PES;
-       dmxdevfilter->pid=params->pid;
-       memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params));
+       dmxdevfilter->type = DMXDEV_TYPE_PES;
+       memcpy(&dmxdevfilter->params, params,
+              sizeof(struct dmx_pes_filter_params));
 
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
 
-       if (params->flags&DMX_IMMEDIATE_START)
+       if (params->flags & DMX_IMMEDIATE_START)
                return dvb_dmxdev_filter_start(dmxdevfilter);
 
        return 0;
 }
 
 static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
-               struct file *file, char __user *buf, size_t count, loff_t *ppos)
+                                  struct file *file, char __user *buf,
+                                  size_t count, loff_t *ppos)
 {
        int result, hcount;
-       int done=0;
-
-       if (dfil->todo<=0) {
-               hcount=3+dfil->todo;
-               if (hcount>count)
-                       hcount=count;
-               result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
-                                       buf, hcount, ppos);
-               if (result<0) {
-                       dfil->todo=0;
+       int done = 0;
+
+       if (dfil->todo <= 0) {
+               hcount = 3 + dfil->todo;
+               if (hcount > count)
+                       hcount = count;
+               result = dvb_dmxdev_buffer_read(&dfil->buffer,
+                                               file->f_flags & O_NONBLOCK,
+                                               buf, hcount, ppos);
+               if (result < 0) {
+                       dfil->todo = 0;
                        return result;
                }
-               if (copy_from_user(dfil->secheader-dfil->todo, buf, result))
+               if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
                        return -EFAULT;
-               buf+=result;
-               done=result;
-               count-=result;
-               dfil->todo-=result;
-               if (dfil->todo>-3)
+               buf += result;
+               done = result;
+               count -= result;
+               dfil->todo -= result;
+               if (dfil->todo > -3)
                        return done;
-               dfil->todo=((dfil->secheader[1]<<8)|dfil->secheader[2])&0xfff;
+               dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
                if (!count)
                        return done;
        }
-       if (count>dfil->todo)
-               count=dfil->todo;
-       result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
-                               buf, count, ppos);
-       if (result<0)
+       if (count > dfil->todo)
+               count = dfil->todo;
+       result = dvb_dmxdev_buffer_read(&dfil->buffer,
+                                       file->f_flags & O_NONBLOCK,
+                                       buf, count, ppos);
+       if (result < 0)
                return result;
-       dfil->todo-=result;
-       return (result+done);
+       dfil->todo -= result;
+       return (result + done);
 }
 
-
 static ssize_t
-dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+dvb_demux_read(struct file *file, char __user *buf, size_t count,
+              loff_t *ppos)
 {
-       struct dmxdev_filter *dmxdevfilter= file->private_data;
-       int ret=0;
+       struct dmxdev_filter *dmxdevfilter = file->private_data;
+       int ret;
 
-       if (down_interruptible(&dmxdevfilter->mutex))
+       if (mutex_lock_interruptible(&dmxdevfilter->mutex))
                return -ERESTARTSYS;
 
-       if (dmxdevfilter->type==DMXDEV_TYPE_SEC)
-               ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
+       if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
+               ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
        else
-               ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
-                                    file->f_flags&O_NONBLOCK,
-                                    buf, count, ppos);
+               ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
+                                            file->f_flags & O_NONBLOCK,
+                                            buf, count, ppos);
 
-       up(&dmxdevfilter->mutex);
+       mutex_unlock(&dmxdevfilter->mutex);
        return ret;
 }
 
-
 static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
                              unsigned int cmd, void *parg)
 {
        struct dmxdev_filter *dmxdevfilter = file->private_data;
-       struct dmxdev *dmxdev=dmxdevfilter->dev;
-       unsigned long arg=(unsigned long) parg;
-       int ret=0;
+       struct dmxdev *dmxdev = dmxdevfilter->dev;
+       unsigned long arg = (unsigned long)parg;
+       int ret = 0;
 
-       if (down_interruptible (&dmxdev->mutex))
+       if (mutex_lock_interruptible(&dmxdev->mutex))
                return -ERESTARTSYS;
 
        switch (cmd) {
        case DMX_START:
-               if (down_interruptible(&dmxdevfilter->mutex)) {
-                       up(&dmxdev->mutex);
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
                        return -ERESTARTSYS;
                }
-               if (dmxdevfilter->state<DMXDEV_STATE_SET)
+               if (dmxdevfilter->state < DMXDEV_STATE_SET)
                        ret = -EINVAL;
                else
                        ret = dvb_dmxdev_filter_start(dmxdevfilter);
-               up(&dmxdevfilter->mutex);
+               mutex_unlock(&dmxdevfilter->mutex);
                break;
 
        case DMX_STOP:
-               if (down_interruptible(&dmxdevfilter->mutex)) {
-                       up(&dmxdev->mutex);
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
                        return -ERESTARTSYS;
                }
-               ret=dvb_dmxdev_filter_stop(dmxdevfilter);
-               up(&dmxdevfilter->mutex);
+               ret = dvb_dmxdev_filter_stop(dmxdevfilter);
+               mutex_unlock(&dmxdevfilter->mutex);
                break;
 
        case DMX_SET_FILTER:
-               if (down_interruptible(&dmxdevfilter->mutex)) {
-                       up(&dmxdev->mutex);
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
                        return -ERESTARTSYS;
                }
-               ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter,
-                                   (struct dmx_sct_filter_params *)parg);
-               up(&dmxdevfilter->mutex);
+               ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
+               mutex_unlock(&dmxdevfilter->mutex);
                break;
 
        case DMX_SET_PES_FILTER:
-               if (down_interruptible(&dmxdevfilter->mutex)) {
-                       up(&dmxdev->mutex);
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
                        return -ERESTARTSYS;
                }
-               ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter,
-                                              (struct dmx_pes_filter_params *)parg);
-               up(&dmxdevfilter->mutex);
+               ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
+               mutex_unlock(&dmxdevfilter->mutex);
                break;
 
        case DMX_SET_BUFFER_SIZE:
-               if (down_interruptible(&dmxdevfilter->mutex)) {
-                       up(&dmxdev->mutex);
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
                        return -ERESTARTSYS;
                }
-               ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
-               up(&dmxdevfilter->mutex);
+               ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
+               mutex_unlock(&dmxdevfilter->mutex);
                break;
 
        case DMX_GET_EVENT:
@@ -923,10 +870,10 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
 
        case DMX_GET_PES_PIDS:
                if (!dmxdev->demux->get_pes_pids) {
-                       ret=-EINVAL;
+                       ret = -EINVAL;
                        break;
                }
-               dmxdev->demux->get_pes_pids(dmxdev->demux, (u16 *)parg);
+               dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
                break;
 
        case DMX_GET_CAPS:
@@ -947,19 +894,20 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
 
        case DMX_GET_STC:
                if (!dmxdev->demux->get_stc) {
-                       ret=-EINVAL;
+                       ret = -EINVAL;
                        break;
                }
                ret = dmxdev->demux->get_stc(dmxdev->demux,
-                               ((struct dmx_stc *)parg)->num,
-                               &((struct dmx_stc *)parg)->stc,
-                               &((struct dmx_stc *)parg)->base);
+                                            ((struct dmx_stc *)parg)->num,
+                                            &((struct dmx_stc *)parg)->stc,
+                                            &((struct dmx_stc *)parg)->base);
                break;
 
        default:
-               ret=-EINVAL;
+               ret = -EINVAL;
+               break;
        }
-       up(&dmxdev->mutex);
+       mutex_unlock(&dmxdev->mutex);
        return ret;
 }
 
@@ -969,8 +917,7 @@ static int dvb_demux_ioctl(struct inode *inode, struct file *file,
        return dvb_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl);
 }
 
-
-static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
+static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
 {
        struct dmxdev_filter *dmxdevfilter = file->private_data;
        unsigned int mask = 0;
@@ -988,13 +935,12 @@ static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
        if (dmxdevfilter->buffer.error)
                mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
 
-       if (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite)
+       if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
                mask |= (POLLIN | POLLRDNORM | POLLPRI);
 
        return mask;
 }
 
-
 static int dvb_demux_release(struct inode *inode, struct file *file)
 {
        struct dmxdev_filter *dmxdevfilter = file->private_data;
@@ -1003,72 +949,67 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
        return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
 }
 
-
 static struct file_operations dvb_demux_fops = {
-       .owner          = THIS_MODULE,
-       .read           = dvb_demux_read,
-       .ioctl          = dvb_demux_ioctl,
-       .open           = dvb_demux_open,
-       .release        = dvb_demux_release,
-       .poll           = dvb_demux_poll,
+       .owner = THIS_MODULE,
+       .read = dvb_demux_read,
+       .ioctl = dvb_demux_ioctl,
+       .open = dvb_demux_open,
+       .release = dvb_demux_release,
+       .poll = dvb_demux_poll,
 };
 
-
 static struct dvb_device dvbdev_demux = {
-       .priv           = NULL,
-       .users          = 1,
-       .writers        = 1,
-       .fops           = &dvb_demux_fops
+       .priv = NULL,
+       .users = 1,
+       .writers = 1,
+       .fops = &dvb_demux_fops
 };
 
-
 static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
-                    unsigned int cmd, void *parg)
+                           unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
+       int ret;
 
-       int ret=0;
-
-       if (down_interruptible (&dmxdev->mutex))
+       if (mutex_lock_interruptible(&dmxdev->mutex))
                return -ERESTARTSYS;
 
        switch (cmd) {
        case DMX_SET_BUFFER_SIZE:
                // FIXME: implement
-               ret=0;
+               ret = 0;
                break;
 
        default:
-               ret=-EINVAL;
+               ret = -EINVAL;
+               break;
        }
-       up(&dmxdev->mutex);
+       mutex_unlock(&dmxdev->mutex);
        return ret;
 }
 
-
 static int dvb_dvr_ioctl(struct inode *inode, struct file *file,
-                 unsigned int cmd, unsigned long arg)
+                        unsigned int cmd, unsigned long arg)
 {
        return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl);
 }
 
-
-static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait)
+static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
        unsigned int mask = 0;
 
-       dprintk ("function : %s\n", __FUNCTION__);
+       dprintk("function : %s\n", __FUNCTION__);
 
        poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
 
-       if ((file->f_flags&O_ACCMODE) == O_RDONLY) {
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
                if (dmxdev->dvr_buffer.error)
                        mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
 
-               if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite)
+               if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
                        mask |= (POLLIN | POLLRDNORM | POLLPRI);
        } else
                mask |= (POLLOUT | POLLWRNORM | POLLPRI);
@@ -1076,73 +1017,63 @@ static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait)
        return mask;
 }
 
-
 static struct file_operations dvb_dvr_fops = {
-       .owner          = THIS_MODULE,
-       .read           = dvb_dvr_read,
-       .write          = dvb_dvr_write,
-       .ioctl          = dvb_dvr_ioctl,
-       .open           = dvb_dvr_open,
-       .release        = dvb_dvr_release,
-       .poll           = dvb_dvr_poll,
+       .owner = THIS_MODULE,
+       .read = dvb_dvr_read,
+       .write = dvb_dvr_write,
+       .ioctl = dvb_dvr_ioctl,
+       .open = dvb_dvr_open,
+       .release = dvb_dvr_release,
+       .poll = dvb_dvr_poll,
 };
 
 static struct dvb_device dvbdev_dvr = {
-       .priv           = NULL,
-       .users          = 1,
-       .writers        = 1,
-       .fops           = &dvb_dvr_fops
+       .priv = NULL,
+       .users = 1,
+       .writers = 1,
+       .fops = &dvb_dvr_fops
 };
 
-int
-dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
+int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
 {
        int i;
 
        if (dmxdev->demux->open(dmxdev->demux) < 0)
                return -EUSERS;
 
-       dmxdev->filter = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_filter));
+       dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
        if (!dmxdev->filter)
                return -ENOMEM;
 
-       dmxdev->dvr = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_dvr));
-       if (!dmxdev->dvr) {
-               vfree(dmxdev->filter);
-               dmxdev->filter = NULL;
-               return -ENOMEM;
-       }
-
-       sema_init(&dmxdev->mutex, 1);
+       mutex_init(&dmxdev->mutex);
        spin_lock_init(&dmxdev->lock);
-       for (i=0; i<dmxdev->filternum; i++) {
-               dmxdev->filter[i].dev=dmxdev;
-               dmxdev->filter[i].buffer.data=NULL;
-               dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
-               dmxdev->dvr[i].dev=dmxdev;
-               dmxdev->dvr[i].buffer.data=NULL;
-               dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE);
+       for (i = 0; i < dmxdev->filternum; i++) {
+               dmxdev->filter[i].dev = dmxdev;
+               dmxdev->filter[i].buffer.data = NULL;
+               dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
+                                           DMXDEV_STATE_FREE);
        }
 
-       dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX);
-       dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR);
+       dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
+                           DVB_DEVICE_DEMUX);
+       dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
+                           dmxdev, DVB_DEVICE_DVR);
 
-       dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
+       dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
 
        return 0;
 }
+
 EXPORT_SYMBOL(dvb_dmxdev_init);
 
-void
-dvb_dmxdev_release(struct dmxdev *dmxdev)
+void dvb_dmxdev_release(struct dmxdev *dmxdev)
 {
        dvb_unregister_device(dmxdev->dvbdev);
        dvb_unregister_device(dmxdev->dvr_dvbdev);
 
        vfree(dmxdev->filter);
-       dmxdev->filter=NULL;
-       vfree(dmxdev->dvr);
-       dmxdev->dvr=NULL;
+       dmxdev->filter = NULL;
        dmxdev->demux->close(dmxdev->demux);
 }
+
 EXPORT_SYMBOL(dvb_dmxdev_release);
index fd72920..d2bee9f 100644 (file)
 #include <linux/wait.h>
 #include <linux/fs.h>
 #include <linux/string.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <linux/dvb/dmx.h>
 
 #include "dvbdev.h"
 #include "demux.h"
+#include "dvb_ringbuffer.h"
 
-enum dmxdevype {
+enum dmxdev_type {
        DMXDEV_TYPE_NONE,
        DMXDEV_TYPE_SEC,
        DMXDEV_TYPE_PES,
@@ -52,18 +53,7 @@ enum dmxdev_state {
        DMXDEV_STATE_TIMEDOUT
 };
 
-struct dmxdev_buffer {
-       u8 *data;
-       int size;
-       int pread;
-       int pwrite;
-       wait_queue_head_t queue;
-       int error;
-};
-
 struct dmxdev_filter {
-       struct dvb_device *dvbdev;
-
        union {
                struct dmx_section_filter *sec;
        } filter;
@@ -78,26 +68,17 @@ struct dmxdev_filter {
                struct dmx_pes_filter_params pes;
        } params;
 
-       int type;
+       enum dmxdev_type type;
        enum dmxdev_state state;
        struct dmxdev *dev;
-       struct dmxdev_buffer buffer;
+       struct dvb_ringbuffer buffer;
 
-       struct semaphore mutex;
+       struct mutex mutex;
 
        /* only for sections */
        struct timer_list timer;
        int todo;
        u8 secheader[3];
-
-       u16 pid;
-};
-
-
-struct dmxdev_dvr {
-       int state;
-       struct dmxdev *dev;
-       struct dmxdev_buffer buffer;
 };
 
 
@@ -106,7 +87,6 @@ struct dmxdev {
        struct dvb_device *dvr_dvbdev;
 
        struct dmxdev_filter *filter;
-       struct dmxdev_dvr *dvr;
        struct dmx_demux *demux;
 
        int filternum;
@@ -114,10 +94,10 @@ struct dmxdev {
 #define DMXDEV_CAP_DUPLEX 1
        struct dmx_frontend *dvr_orig_fe;
 
-       struct dmxdev_buffer dvr_buffer;
+       struct dvb_ringbuffer dvr_buffer;
 #define DVR_BUFFER_SIZE (10*188*1024)
 
-       struct semaphore mutex;
+       struct mutex mutex;
        spinlock_t lock;
 };
 
index b4c899b..83ec5e0 100644 (file)
@@ -589,18 +589,18 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
        if (pid > DMX_MAX_PID)
                return -EINVAL;
 
-       if (down_interruptible(&demux->mutex))
+       if (mutex_lock_interruptible(&demux->mutex))
                return -ERESTARTSYS;
 
        if (ts_type & TS_DECODER) {
                if (pes_type >= DMX_TS_PES_OTHER) {
-                       up(&demux->mutex);
+                       mutex_unlock(&demux->mutex);
                        return -EINVAL;
                }
 
                if (demux->pesfilter[pes_type] &&
                    demux->pesfilter[pes_type] != feed) {
-                       up(&demux->mutex);
+                       mutex_unlock(&demux->mutex);
                        return -EINVAL;
                }
 
@@ -622,14 +622,14 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
 #else
                feed->buffer = vmalloc(feed->buffer_size);
                if (!feed->buffer) {
-                       up(&demux->mutex);
+                       mutex_unlock(&demux->mutex);
                        return -ENOMEM;
                }
 #endif
        }
 
        feed->state = DMX_STATE_READY;
-       up(&demux->mutex);
+       mutex_unlock(&demux->mutex);
 
        return 0;
 }
@@ -640,21 +640,21 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
        struct dvb_demux *demux = feed->demux;
        int ret;
 
-       if (down_interruptible(&demux->mutex))
+       if (mutex_lock_interruptible(&demux->mutex))
                return -ERESTARTSYS;
 
        if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
-               up(&demux->mutex);
+               mutex_unlock(&demux->mutex);
                return -EINVAL;
        }
 
        if (!demux->start_feed) {
-               up(&demux->mutex);
+               mutex_unlock(&demux->mutex);
                return -ENODEV;
        }
 
        if ((ret = demux->start_feed(feed)) < 0) {
-               up(&demux->mutex);
+               mutex_unlock(&demux->mutex);
                return ret;
        }
 
@@ -662,7 +662,7 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
        ts_feed->is_filtering = 1;
        feed->state = DMX_STATE_GO;
        spin_unlock_irq(&demux->lock);
-       up(&demux->mutex);
+       mutex_unlock(&demux->mutex);
 
        return 0;
 }
@@ -673,16 +673,16 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
        struct dvb_demux *demux = feed->demux;
        int ret;
 
-       if (down_interruptible(&demux->mutex))
+       if (mutex_lock_interruptible(&demux->mutex))
                return -ERESTARTSYS;
 
        if (feed->state < DMX_STATE_GO) {
-               up(&demux->mutex);
+               mutex_unlock(&demux->mutex);
                return -EINVAL;
        }
 
        if (!demux->stop_feed) {
-               up(&demux->mutex);
+               mutex_unlock(&demux->mutex);
                return -ENODEV;
        }
 
@@ -692,7 +692,7 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
        ts_feed->is_filtering = 0;
        feed->state = DMX_STATE_ALLOCATED;
        spin_unlock_irq(&demux->lock);
-       up(&demux->mutex);
+       mutex_unlock(&demux->mutex);
 
        return ret;
 }
@@ -704,11 +704,11 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
        struct dvb_demux *demux = (struct dvb_demux *)dmx;
        struct dvb_demux_feed *feed;
 
-       if (down_interruptible(&demux->mutex))
+       if (mutex_lock_interruptible(&demux->mutex))
                return -ERESTARTSYS;
 
        if (!(feed = dvb_dmx_feed_alloc(demux))) {
-               up(&demux->mutex);
+               mutex_unlock(&demux->mutex);
                return -EBUSY;
        }
 
@@ -729,7 +729,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
 
        if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
                feed->state = DMX_STATE_FREE;
-               up(&demux->mutex);
+               mutex_unlock(&demux->mutex);
                return -EBUSY;
        }
 
@@ -737,7 +737,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
        feed->filter->feed = feed;
        feed->filter->state = DMX_STATE_READY;
 
-       up(&demux->mutex);
+       mutex_unlock(&demux->mutex);
 
        return 0;
 }
@@ -748,11 +748,11 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
        struct dvb_demux *demux = (struct dvb_demux *)dmx;
        struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
 
-       if (down_interruptible(&demux->mutex))
+       if (mutex_lock_interruptible(&demux->mutex))
                return -ERESTARTSYS;
 
        if (feed->state == DMX_STATE_FREE) {
-               up(&demux->mutex);
+               mutex_unlock(&demux->mutex);
                return -EINVAL;
        }
 #ifndef NOBUFS
@@ -770,7 +770,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
        if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
                demux->pesfilter[feed->pes_type] = NULL;
 
-       up(&demux->mutex);
+       mutex_unlock(&demux->mutex);
        return 0;
 }
 
@@ -785,12 +785,12 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
        struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
        struct dvb_demux_filter *dvbdmxfilter;
 
-       if (down_interruptible(&dvbdemux->mutex))
+       if (mutex_lock_interruptible(&dvbdemux->mutex))
                return -ERESTARTSYS;
 
        dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
        if (!dvbdmxfilter) {
-               up(&dvbdemux->mutex);
+               mutex_unlock(&dvbdemux->mutex);
                return -EBUSY;
        }
 
@@ -805,7 +805,7 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
        dvbdmxfeed->filter = dvbdmxfilter;
        spin_unlock_irq(&dvbdemux->lock);
 
-       up(&dvbdemux->mutex);
+       mutex_unlock(&dvbdemux->mutex);
        return 0;
 }
 
@@ -819,7 +819,7 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed,
        if (pid > 0x1fff)
                return -EINVAL;
 
-       if (down_interruptible(&dvbdmx->mutex))
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
                return -ERESTARTSYS;
 
        dvb_demux_feed_add(dvbdmxfeed);
@@ -833,13 +833,13 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed,
 #else
        dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
        if (!dvbdmxfeed->buffer) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return -ENOMEM;
        }
 #endif
 
        dvbdmxfeed->state = DMX_STATE_READY;
-       up(&dvbdmx->mutex);
+       mutex_unlock(&dvbdmx->mutex);
        return 0;
 }
 
@@ -871,16 +871,16 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
        struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
        int ret;
 
-       if (down_interruptible(&dvbdmx->mutex))
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
                return -ERESTARTSYS;
 
        if (feed->is_filtering) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return -EBUSY;
        }
 
        if (!dvbdmxfeed->filter) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return -EINVAL;
        }
 
@@ -890,14 +890,14 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
        dvbdmxfeed->feed.sec.seclen = 0;
 
        if (!dvbdmx->start_feed) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return -ENODEV;
        }
 
        prepare_secfilters(dvbdmxfeed);
 
        if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return ret;
        }
 
@@ -906,7 +906,7 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
        dvbdmxfeed->state = DMX_STATE_GO;
        spin_unlock_irq(&dvbdmx->lock);
 
-       up(&dvbdmx->mutex);
+       mutex_unlock(&dvbdmx->mutex);
        return 0;
 }
 
@@ -916,11 +916,11 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
        struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
        int ret;
 
-       if (down_interruptible(&dvbdmx->mutex))
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
                return -ERESTARTSYS;
 
        if (!dvbdmx->stop_feed) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return -ENODEV;
        }
 
@@ -931,7 +931,7 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
        feed->is_filtering = 0;
        spin_unlock_irq(&dvbdmx->lock);
 
-       up(&dvbdmx->mutex);
+       mutex_unlock(&dvbdmx->mutex);
        return ret;
 }
 
@@ -942,11 +942,11 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
        struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
        struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
 
-       if (down_interruptible(&dvbdmx->mutex))
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
                return -ERESTARTSYS;
 
        if (dvbdmxfilter->feed != dvbdmxfeed) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return -EINVAL;
        }
 
@@ -966,7 +966,7 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
 
        dvbdmxfilter->state = DMX_STATE_FREE;
        spin_unlock_irq(&dvbdmx->lock);
-       up(&dvbdmx->mutex);
+       mutex_unlock(&dvbdmx->mutex);
        return 0;
 }
 
@@ -977,11 +977,11 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
        struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
        struct dvb_demux_feed *dvbdmxfeed;
 
-       if (down_interruptible(&dvbdmx->mutex))
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
                return -ERESTARTSYS;
 
        if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return -EBUSY;
        }
 
@@ -1006,7 +1006,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
        (*feed)->stop_filtering = dmx_section_feed_stop_filtering;
        (*feed)->release_filter = dmx_section_feed_release_filter;
 
-       up(&dvbdmx->mutex);
+       mutex_unlock(&dvbdmx->mutex);
        return 0;
 }
 
@@ -1016,11 +1016,11 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
        struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
        struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
 
-       if (down_interruptible(&dvbdmx->mutex))
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
                return -ERESTARTSYS;
 
        if (dvbdmxfeed->state == DMX_STATE_FREE) {
-               up(&dvbdmx->mutex);
+               mutex_unlock(&dvbdmx->mutex);
                return -EINVAL;
        }
 #ifndef NOBUFS
@@ -1033,7 +1033,7 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
 
        dvbdmxfeed->pid = 0xffff;
 
-       up(&dvbdmx->mutex);
+       mutex_unlock(&dvbdmx->mutex);
        return 0;
 }
 
@@ -1071,10 +1071,10 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
        if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
                return -EINVAL;
 
-       if (down_interruptible(&dvbdemux->mutex))
+       if (mutex_lock_interruptible(&dvbdemux->mutex))
                return -ERESTARTSYS;
        dvb_dmx_swfilter(dvbdemux, buf, count);
-       up(&dvbdemux->mutex);
+       mutex_unlock(&dvbdemux->mutex);
 
        if (signal_pending(current))
                return -EINTR;
@@ -1126,11 +1126,11 @@ static int dvbdmx_connect_frontend(struct dmx_demux *demux,
        if (demux->frontend)
                return -EINVAL;
 
-       if (down_interruptible(&dvbdemux->mutex))
+       if (mutex_lock_interruptible(&dvbdemux->mutex))
                return -ERESTARTSYS;
 
        demux->frontend = frontend;
-       up(&dvbdemux->mutex);
+       mutex_unlock(&dvbdemux->mutex);
        return 0;
 }
 
@@ -1138,11 +1138,11 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
 {
        struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
 
-       if (down_interruptible(&dvbdemux->mutex))
+       if (mutex_lock_interruptible(&dvbdemux->mutex))
                return -ERESTARTSYS;
 
        demux->frontend = NULL;
-       up(&dvbdemux->mutex);
+       mutex_unlock(&dvbdemux->mutex);
        return 0;
 }
 
@@ -1215,7 +1215,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
        dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
        dmx->get_pes_pids = dvbdmx_get_pes_pids;
 
-       sema_init(&dvbdemux->mutex, 1);
+       mutex_init(&dvbdemux->mutex);
        spin_lock_init(&dvbdemux->lock);
 
        return 0;
index 0cc8883..2c5f915 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/time.h>
 #include <linux/timer.h>
 #include <linux/spinlock.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "demux.h"
 
@@ -125,7 +125,7 @@ struct dvb_demux {
        u8 tsbuf[204];
        int tsbufp;
 
-       struct semaphore mutex;
+       struct mutex mutex;
        spinlock_t lock;
 };
 
index 771f32d..2c3ea8f 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/suspend.h>
 #include <linux/jiffies.h>
 #include <asm/processor.h>
-#include <asm/semaphore.h>
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
@@ -50,13 +49,13 @@ static int dvb_powerdown_on_sleep = 1;
 
 module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
 MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
-module_param(dvb_shutdown_timeout, int, 0444);
+module_param(dvb_shutdown_timeout, int, 0644);
 MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
-module_param(dvb_force_auto_inversion, int, 0444);
+module_param(dvb_force_auto_inversion, int, 0644);
 MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
-module_param(dvb_override_tune_delay, int, 0444);
+module_param(dvb_override_tune_delay, int, 0644);
 MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
-module_param(dvb_powerdown_on_sleep, int, 0444);
+module_param(dvb_powerdown_on_sleep, int, 0644);
 MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
 
 #define dprintk if (dvb_frontend_debug) printk
@@ -88,7 +87,7 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB vola
  * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
  */
 
-static DECLARE_MUTEX(frontend_mutex);
+static DEFINE_MUTEX(frontend_mutex);
 
 struct dvb_frontend_private {
 
@@ -1021,12 +1020,12 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
 
        dprintk ("%s\n", __FUNCTION__);
 
-       if (down_interruptible (&frontend_mutex))
+       if (mutex_lock_interruptible(&frontend_mutex))
                return -ERESTARTSYS;
 
        fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
        if (fe->frontend_priv == NULL) {
-               up(&frontend_mutex);
+               mutex_unlock(&frontend_mutex);
                return -ENOMEM;
        }
        fepriv = fe->frontend_priv;
@@ -1045,7 +1044,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
        dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
                             fe, DVB_DEVICE_FRONTEND);
 
-       up (&frontend_mutex);
+       mutex_unlock(&frontend_mutex);
        return 0;
 }
 EXPORT_SYMBOL(dvb_register_frontend);
@@ -1055,7 +1054,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        dprintk ("%s\n", __FUNCTION__);
 
-       down (&frontend_mutex);
+       mutex_lock(&frontend_mutex);
        dvb_unregister_device (fepriv->dvbdev);
        dvb_frontend_stop (fe);
        if (fe->ops->release)
@@ -1064,7 +1063,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
                printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
        /* fe is invalid now */
        kfree(fepriv);
-       up (&frontend_mutex);
+       mutex_unlock(&frontend_mutex);
        return 0;
 }
 EXPORT_SYMBOL(dvb_unregister_frontend);
index 70a6d14..d5aee5a 100644 (file)
@@ -104,6 +104,7 @@ struct dvb_frontend {
        struct dvb_adapter *dvb;
        void* demodulator_priv;
        void* frontend_priv;
+       void* misc_priv;
 };
 
 extern int dvb_register_frontend(struct dvb_adapter* dvb,
index 6711eb6..2f0f358 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/uio.h>
 #include <asm/uaccess.h>
 #include <linux/crc32.h>
+#include <linux/mutex.h>
 
 #include "dvb_demux.h"
 #include "dvb_net.h"
@@ -151,8 +152,7 @@ struct dvb_net_priv {
        unsigned char ule_bridged;              /* Whether the ULE_BRIDGED extension header was found. */
        int ule_sndu_remain;                    /* Nr. of bytes still required for current ULE SNDU. */
        unsigned long ts_count;                 /* Current ts cell counter. */
-
-       struct semaphore mutex;
+       struct mutex mutex;
 };
 
 
@@ -889,7 +889,7 @@ static int dvb_net_feed_start(struct net_device *dev)
        unsigned char *mac = (unsigned char *) dev->dev_addr;
 
        dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode);
-       down(&priv->mutex);
+       mutex_lock(&priv->mutex);
        if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
                printk("%s: BUG %d\n", __FUNCTION__, __LINE__);
 
@@ -974,7 +974,7 @@ static int dvb_net_feed_start(struct net_device *dev)
                ret = -EINVAL;
 
 error:
-       up(&priv->mutex);
+       mutex_unlock(&priv->mutex);
        return ret;
 }
 
@@ -984,7 +984,7 @@ static int dvb_net_feed_stop(struct net_device *dev)
        int i, ret = 0;
 
        dprintk("%s\n", __FUNCTION__);
-       down(&priv->mutex);
+       mutex_lock(&priv->mutex);
        if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
                if (priv->secfeed) {
                        if (priv->secfeed->is_filtering) {
@@ -1026,7 +1026,7 @@ static int dvb_net_feed_stop(struct net_device *dev)
                        printk("%s: no ts feed to stop\n", dev->name);
        } else
                ret = -EINVAL;
-       up(&priv->mutex);
+       mutex_unlock(&priv->mutex);
        return ret;
 }
 
@@ -1208,7 +1208,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
 
        INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net);
        INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net);
-       init_MUTEX(&priv->mutex);
+       mutex_init(&priv->mutex);
 
        net->base_addr = pid;
 
index 77ad241..c972fe0 100644 (file)
@@ -45,6 +45,7 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
        rbuf->pread=rbuf->pwrite=0;
        rbuf->data=data;
        rbuf->size=len;
+       rbuf->error=0;
 
        init_waitqueue_head(&rbuf->queue);
 
@@ -87,6 +88,7 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
 void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
 {
        rbuf->pread = rbuf->pwrite;
+       rbuf->error = 0;
 }
 
 
index 6d25609..d97714e 100644 (file)
@@ -35,6 +35,7 @@ struct dvb_ringbuffer {
        ssize_t           size;
        ssize_t           pread;
        ssize_t           pwrite;
+       int               error;
 
        wait_queue_head_t queue;
        spinlock_t        lock;
index 162f979..e14bf43 100644 (file)
@@ -77,7 +77,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i;
 
-       if (down_interruptible(&d->i2c_sem) < 0)
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
 
        if (num > 2)
@@ -126,7 +126,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
                }
        }
 
-       up(&d->i2c_sem);
+       mutex_unlock(&d->i2c_mutex);
        return i;
 }
 
index 269d899..2d52b76 100644 (file)
@@ -128,7 +128,7 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i;
 
-       if (down_interruptible(&d->i2c_sem) < 0)
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
 
        if (num > 2)
@@ -146,7 +146,7 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
                                break;
        }
 
-       up(&d->i2c_sem);
+       mutex_unlock(&d->i2c_mutex);
        return i;
 }
 
index caa1346..91136c0 100644 (file)
@@ -48,7 +48,7 @@ static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i;
 
-       if (down_interruptible(&d->i2c_sem) < 0)
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
 
        if (num > 2)
@@ -67,7 +67,7 @@ static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
                                break;
        }
 
-       up(&d->i2c_sem);
+       mutex_unlock(&d->i2c_mutex);
        return i;
 }
 
index ce34a55..a1705ec 100644 (file)
@@ -42,8 +42,8 @@ static int dvb_usb_init(struct dvb_usb_device *d)
 {
        int ret = 0;
 
-       sema_init(&d->usb_sem, 1);
-       sema_init(&d->i2c_sem, 1);
+       mutex_init(&d->usb_mutex);
+       mutex_init(&d->i2c_mutex);
 
        d->state = DVB_USB_STATE_INIT;
 
index ee82197..9002f35 100644 (file)
@@ -21,7 +21,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
        if (wbuf == NULL || wlen == 0)
                return -EINVAL;
 
-       if ((ret = down_interruptible(&d->usb_sem)))
+       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
                return ret;
 
        deb_xfer(">>> ");
@@ -53,7 +53,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
                }
        }
 
-       up(&d->usb_sem);
+       mutex_unlock(&d->usb_mutex);
        return ret;
 }
 EXPORT_SYMBOL(dvb_usb_generic_rw);
index d4909e5..fead958 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/firmware.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "dvb_demux.h"
@@ -227,8 +228,8 @@ struct dvb_usb_properties {
  * @feedcount: number of reqested feeds (used for streaming-activation)
  * @pid_filtering: is hardware pid_filtering used or not.
  *
- * @usb_sem: semaphore of USB control messages (reading needs two messages)
- * @i2c_sem: semaphore for i2c-transfers
+ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+ * @i2c_mutex: semaphore for i2c-transfers
  *
  * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
  * @pll_addr: I2C address of the tuner for programming
@@ -283,10 +284,10 @@ struct dvb_usb_device {
        int pid_filtering;
 
        /* locking */
-       struct semaphore usb_sem;
+       struct mutex usb_mutex;
 
        /* i2c */
-       struct semaphore i2c_sem;
+       struct mutex i2c_mutex;
        struct i2c_adapter i2c_adap;
 
        /* tuner programming information */
index 4a95eca..b2f098a 100644 (file)
@@ -75,7 +75,7 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il
 {
        int ret;
 
-       if ((ret = down_interruptible(&d->usb_sem)))
+       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
                return ret;
 
        if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0)
@@ -84,7 +84,7 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il
        ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
 
 unlock:
-       up(&d->usb_sem);
+       mutex_unlock(&d->usb_mutex);
 
        return ret;
 }
index 3835235..8ea3834 100644 (file)
@@ -38,7 +38,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
        deb_xfer("out buffer: ");
        debug_dump(outbuf,outlen+1,deb_xfer);
 
-       if ((ret = down_interruptible(&d->usb_sem)))
+       if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
                return ret;
 
        if (usb_control_msg(d->udev,
@@ -68,7 +68,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
                memcpy(in,&inbuf[1],inlen);
 
 unlock:
-       up(&d->usb_sem);
+       mutex_unlock(&d->usb_mutex);
 
        return ret;
 }
index c676b1e..9423316 100644 (file)
@@ -116,6 +116,12 @@ config DVB_MT352
        help
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
+config DVB_ZL10353
+       tristate "Zarlink ZL10353 based"
+       depends on DVB_CORE
+       help
+         A DVB-T tuner module. Say Y when you want to support this frontend.
+
 config DVB_DIB3000MB
        tristate "DiBcom 3000M-B"
        depends on DVB_CORE
@@ -155,7 +161,7 @@ comment "ATSC (North American/Korean Terresterial DTV) frontends"
        depends on DVB_CORE
 
 config DVB_NXT200X
-       tristate "Nextwave NXT2002/NXT2004 based"
+       tristate "NxtWave Communications NXT2002/NXT2004 based"
        depends on DVB_CORE
        select FW_LOADER
        help
@@ -169,14 +175,14 @@ config DVB_NXT200X
          or /lib/firmware (depending on configuration of firmware hotplug).
 
 config DVB_OR51211
-       tristate "or51211 based (pcHDTV HD2000 card)"
+       tristate "Oren OR51211 based"
        depends on DVB_CORE
        select FW_LOADER
        help
          An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
 config DVB_OR51132
-       tristate "OR51132 based (pcHDTV HD3000 card)"
+       tristate "Oren OR51132 based"
        depends on DVB_CORE
        select FW_LOADER
        help
index 1af769c..d09b607 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
 obj-$(CONFIG_DVB_SP887X) += sp887x.o
 obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
 obj-$(CONFIG_DVB_MT352) += mt352.o
+obj-$(CONFIG_DVB_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_CX22702) += cx22702.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
index caaee89..1708a1d 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/jiffies.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "bcm3510.h"
@@ -52,7 +53,7 @@ struct bcm3510_state {
        struct dvb_frontend frontend;
 
        /* demodulator private data */
-       struct semaphore hab_sem;
+       struct mutex hab_mutex;
        u8 firmware_loaded:1;
 
        unsigned long next_status_check;
@@ -213,7 +214,7 @@ static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *ob
        dbufout(ob,olen+2,deb_hab);
        deb_hab("\n");
 
-       if (down_interruptible(&st->hab_sem) < 0)
+       if (mutex_lock_interruptible(&st->hab_mutex) < 0)
                return -EAGAIN;
 
        if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
@@ -226,7 +227,7 @@ static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *ob
 
        memcpy(ibuf,&ib[2],ilen);
 error:
-       up(&st->hab_sem);
+       mutex_unlock(&st->hab_mutex);
        return ret;
 }
 
@@ -796,7 +797,7 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
        state->frontend.ops = &state->ops;
        state->frontend.demodulator_priv = state;
 
-       sema_init(&state->hab_sem, 1);
+       mutex_init(&state->hab_mutex);
 
        if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
                goto error;
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
new file mode 100644 (file)
index 0000000..78573b2
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * bsbe1.h - ALPS BSBE1 tuner support (moved from av7110.c)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSBE1_H
+#define BSBE1_H
+
+static u8 alps_bsbe1_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x30,
+       0x03, 0x00,
+       0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+       0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+       0x06, 0x40,   /* DAC not used, set to high impendance mode */
+       0x07, 0x00,   /* DAC LSB */
+       0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+       0x09, 0x00,   /* FIFO */
+       0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+       0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+       0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+       0x10, 0x3f,   // AGC2  0x3d
+       0x11, 0x84,
+       0x12, 0xb9,
+       0x15, 0xc9,   // lock detector threshold
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1a, 0x00,
+       0x1f, 0x50,
+       0x20, 0x00,
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+       0x29, 0x1e,  // 1/2 threshold
+       0x2a, 0x14,  // 2/3 threshold
+       0x2b, 0x0f,  // 3/4 threshold
+       0x2c, 0x09,  // 5/6 threshold
+       0x2d, 0x05,  // 7/8 threshold
+       0x2e, 0x01,
+       0x31, 0x1f,  // test all FECs
+       0x32, 0x19,  // viterbi and synchro search
+       0x33, 0xfc,  // rs control
+       0x34, 0x93,  // error control
+       0x0f, 0x92,
+       0xff, 0xff
+};
+
+
+static int alps_bsbe1_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 alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+{
+       int ret;
+       u8 data[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+       if ((params->frequency < 950000) || (params->frequency > 2150000))
+               return -EINVAL;
+
+       div = (params->frequency + (125 - 1)) / 125; // round correctly
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+       data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+
+       ret = i2c_transfer(i2c, &msg, 1);
+       return (ret != 1) ? -EIO : 0;
+}
+
+static struct stv0299_config alps_bsbe1_config = {
+       .demod_address = 0x68,
+       .inittab = alps_bsbe1_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .min_delay_ms = 100,
+       .set_symbol_rate = alps_bsbe1_set_symbol_rate,
+       .pll_set = alps_bsbe1_pll_set,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
new file mode 100644 (file)
index 0000000..2a5366c
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * bsru6.h - ALPS BSRU6 tuner support (moved from budget-ci.c)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSRU6_H
+#define BSRU6_H
+
+static u8 alps_bsru6_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x00,
+       0x03, 0x00,
+       0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+       0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+       0x06, 0x40,   /* DAC not used, set to high impendance mode */
+       0x07, 0x00,   /* DAC LSB */
+       0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+       0x09, 0x00,   /* FIFO */
+       0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+       0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+       0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+       0x10, 0x3f,   // AGC2  0x3d
+       0x11, 0x84,
+       0x12, 0xb9,
+       0x15, 0xc9,   // lock detector threshold
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1a, 0x00,
+       0x1f, 0x50,
+       0x20, 0x00,
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+       0x29, 0x1e,  // 1/2 threshold
+       0x2a, 0x14,  // 2/3 threshold
+       0x2b, 0x0f,  // 3/4 threshold
+       0x2c, 0x09,  // 5/6 threshold
+       0x2d, 0x05,  // 7/8 threshold
+       0x2e, 0x01,
+       0x31, 0x1f,  // test all FECs
+       0x32, 0x19,  // viterbi and synchro search
+       0x33, 0xfc,  // rs control
+       0x34, 0x93,  // error control
+       0x0f, 0x52,
+       0xff, 0xff
+};
+
+static int alps_bsru6_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 alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+{
+       u8 buf[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+       if ((params->frequency < 950000) || (params->frequency > 2150000))
+               return -EINVAL;
+
+       div = (params->frequency + (125 - 1)) / 125;    // round correctly
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+       buf[3] = 0xC4;
+
+       if (params->frequency > 1530000)
+               buf[3] = 0xc0;
+
+       if (i2c_transfer(i2c, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+       .demod_address = 0x68,
+       .inittab = alps_bsru6_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = alps_bsru6_set_symbol_rate,
+       .pll_set = alps_bsru6_pll_set,
+};
+
+#endif
index d15d32c..f3edf8b 100644 (file)
@@ -371,6 +371,15 @@ static int cx24110_initfe(struct dvb_frontend* fe)
        return 0;
 }
 
+static int cx24110_sleep(struct dvb_frontend *fe)
+{
+       struct cx24110_state *state = fe->demodulator_priv;
+
+       if (state->config->pll_sleep)
+                 return state->config->pll_sleep(fe);
+       return 0;
+}
+
 static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
        struct cx24110_state *state = fe->demodulator_priv;
@@ -418,6 +427,9 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
        struct cx24110_state *state = fe->demodulator_priv;
        unsigned long timeout;
 
+       if (cmd->msg_len < 3 || cmd->msg_len > 6)
+               return -EINVAL;  /* not implemented */
+
        for (i = 0; i < cmd->msg_len; i++)
                cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
 
@@ -639,6 +651,7 @@ static struct dvb_frontend_ops cx24110_ops = {
        .release = cx24110_release,
 
        .init = cx24110_initfe,
+       .sleep = cx24110_sleep,
        .set_frontend = cx24110_set_frontend,
        .get_frontend = cx24110_get_frontend,
        .read_status = cx24110_read_status,
index b63ecf2..609ac64 100644 (file)
@@ -35,6 +35,7 @@ struct cx24110_config
        /* PLL maintenance */
        int (*pll_init)(struct dvb_frontend* fe);
        int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+       int (*pll_sleep)(struct dvb_frontend* fe);
 };
 
 extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
index 4dcb605..b6e2c38 100644 (file)
@@ -362,6 +362,63 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
 };
 EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
 
+/*
+ * Philips TD1316 Tuner.
+ */
+static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+{
+       u8 band;
+
+       /* determine band */
+       if (freq < 161000000)
+               band = 1;
+       else if (freq < 444000000)
+               band = 2;
+       else
+               band = 4;
+
+       buf[3] |= band;
+
+       /* setup PLL filter */
+       if (bandwidth == BANDWIDTH_8_MHZ)
+               buf[3] |= 1 << 3;
+}
+
+struct dvb_pll_desc dvb_pll_philips_td1316 = {
+       .name  = "Philips TD1316",
+       .min   =  87000000,
+       .max   = 895000000,
+       .setbw = td1316_bw,
+       .count = 9,
+       .entries = {
+               {  93834000, 36166000, 166666, 0xca, 0x60},
+               { 123834000, 36166000, 166666, 0xca, 0xa0},
+               { 163834000, 36166000, 166666, 0xca, 0xc0},
+               { 253834000, 36166000, 166666, 0xca, 0x60},
+               { 383834000, 36166000, 166666, 0xca, 0xa0},
+               { 443834000, 36166000, 166666, 0xca, 0xc0},
+               { 583834000, 36166000, 166666, 0xca, 0x60},
+               { 793834000, 36166000, 166666, 0xca, 0xa0},
+               { 858834000, 36166000, 166666, 0xca, 0xe0},
+       },
+};
+EXPORT_SYMBOL(dvb_pll_philips_td1316);
+
+/* FE6600 used on DViCO Hybrid */
+struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+       .name = "Thomson FE6600",
+       .min =  44250000,
+       .max = 858000000,
+       .count = 4,
+       .entries = {
+               { 250000000, 36213333, 166667, 0xb4, 0x12 },
+               { 455000000, 36213333, 166667, 0xfe, 0x11 },
+               { 775500000, 36213333, 166667, 0xbc, 0x18 },
+               { 999999999, 36213333, 166667, 0xf4, 0x18 },
+       }
+};
+EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
@@ -391,8 +448,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
        div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
        buf[0] = div >> 8;
        buf[1] = div & 0xff;
-       buf[2] = desc->entries[i].cb1;
-       buf[3] = desc->entries[i].cb2;
+       buf[2] = desc->entries[i].config;
+       buf[3] = desc->entries[i].cb;
 
        if (desc->setbw)
                desc->setbw(buf, freq, bandwidth);
index bb8d4b4..2b84617 100644 (file)
@@ -15,8 +15,8 @@ struct dvb_pll_desc {
                u32 limit;
                u32 offset;
                u32 stepsize;
-               u8  cb1;
-               u8  cb2;
+               u8  config;
+               u8  cb;
        } entries[12];
 };
 
@@ -40,6 +40,9 @@ extern struct dvb_pll_desc dvb_pll_tuv1236d;
 extern struct dvb_pll_desc dvb_pll_tdhu2;
 extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
 extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
+extern struct dvb_pll_desc dvb_pll_philips_td1316;
+
+extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
 
 int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
                      u32 freq, int bandwidth);
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
new file mode 100644 (file)
index 0000000..0dcbe61
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _LNBP21_H
+#define _LNBP21_H
+
+/* system register */
+#define LNBP21_OLF     0x01
+#define LNBP21_OTF     0x02
+#define LNBP21_EN      0x04
+#define LNBP21_VSEL    0x08
+#define LNBP21_LLC     0x10
+#define LNBP21_TEN     0x20
+#define LNBP21_ISEL    0x40
+#define LNBP21_PCL     0x80
+
+struct lnbp21 {
+       u8                      config;
+       u8                      override_or;
+       u8                      override_and;
+       struct i2c_adapter      *i2c;
+       void                    (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+       struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
+                               .buf = &lnbp21->config,
+                               .len = sizeof(lnbp21->config) };
+
+       lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+       switch(voltage) {
+       case SEC_VOLTAGE_OFF:
+               break;
+       case SEC_VOLTAGE_13:
+               lnbp21->config |= LNBP21_EN;
+               break;
+       case SEC_VOLTAGE_18:
+               lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       lnbp21->config |= lnbp21->override_or;
+       lnbp21->config &= lnbp21->override_and;
+
+       return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+       struct i2c_msg msg = {  .addr = 0x08, .flags = 0,
+                               .buf = &lnbp21->config,
+                               .len = sizeof(lnbp21->config) };
+
+       if (arg)
+               lnbp21->config |= LNBP21_LLC;
+       else
+               lnbp21->config &= ~LNBP21_LLC;
+
+       lnbp21->config |= lnbp21->override_or;
+       lnbp21->config &= lnbp21->override_and;
+
+       return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_exit(struct dvb_frontend *fe)
+{
+       struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+       /* LNBP power off */
+       lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+       /* free data & call next release routine */
+       fe->ops->release = lnbp21->release_chain;
+       kfree(fe->misc_priv);
+       fe->misc_priv = NULL;
+       if (fe->ops->release)
+               fe->ops->release(fe);
+}
+
+static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+       struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+
+       if (!lnbp21)
+               return -ENOMEM;
+
+       /* default configuration */
+       lnbp21->config = LNBP21_ISEL;
+
+       /* bits which should be forced to '1' */
+       lnbp21->override_or = override_set;
+
+       /* bits which should be forced to '0' */
+       lnbp21->override_and = ~override_clear;
+
+       /* install release callback */
+       lnbp21->release_chain = fe->ops->release;
+       fe->ops->release = lnbp21_exit;
+
+       /* override frontend ops */
+       fe->ops->set_voltage = lnbp21_set_voltage;
+       fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+       lnbp21->i2c = i2c;
+       fe->misc_priv = lnbp21;
+
+       return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+}
+
+#endif
index c63e9a5..8e8df7b 100644 (file)
@@ -229,7 +229,7 @@ static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
        dprintk("%s\n", __FUNCTION__);
 
        result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
-       msleep(1);
+       msleep(20);
        return result;
 }
 
@@ -502,7 +502,12 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
        const struct firmware *fw;
 
        /* reset + wake up chip */
-       tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
+       if (state->config->xtal_freq == TDA10046_XTAL_4M) {
+               tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
+       } else {
+               dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __FUNCTION__);
+               tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
+       }
        tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
        /* let the clocks recover from sleep */
        msleep(5);
@@ -651,7 +656,7 @@ static int tda10046_init(struct dvb_frontend* fe)
        // tda setup
        tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
        tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
-       tda1004x_write_byteI(state, TDA1004X_CONFC1, 8);      // disable pulse killer
+       tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88);      // enable pulse killer
 
        switch (state->config->agc_config) {
        case TDA10046_AGC_DEFAULT:
@@ -672,6 +677,12 @@ static int tda10046_init(struct dvb_frontend* fe)
                tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
                tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
                break;
+       case TDA10046_AGC_TDA827X_GPL:
+               tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
+               tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
+               tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
+               tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+               break;
        }
        tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
        tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
@@ -683,6 +694,7 @@ static int tda10046_init(struct dvb_frontend* fe)
        tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
        tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
        tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
+       // tda1004x_write_mask(state, 0x50, 0x80, 0x80);         // handle out of guard echoes
        tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
 
        state->initialised = 1;
@@ -1027,6 +1039,7 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status
                if (status == -1)
                        return -EIO;
                cber |= (status << 8);
+               // The address 0x20 should be read to cope with a TDA10046 bug
                tda1004x_read_byte(state, TDA1004X_CBER_RESET);
 
                if (cber != 65535)
@@ -1047,7 +1060,8 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status
                status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
                if (status == -1)
                        return -EIO;
-               vber |= ((status << 16) & 0x0f);
+               vber |= (status & 0x0f) << 16;
+               // The CVBER_LUT should be read to cope with TDA10046 hardware bug
                tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
 
                // if RS has passed some valid TS packets, then we must be
@@ -1161,6 +1175,7 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
        if (tmp < 0)
                return -EIO;
        *ber |= (tmp << 9);
+       // The address 0x20 should be read to cope with a TDA10046 bug
        tda1004x_read_byte(state, TDA1004X_CBER_RESET);
 
        dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
@@ -1187,6 +1202,8 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
                                tda1004x_disable_tuner_i2c(state);
                        }
                }
+               /* set outputs to tristate */
+               tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
                tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
                break;
        }
index 8659c52..cc0c4af 100644 (file)
@@ -35,7 +35,8 @@ enum tda10046_agc {
        TDA10046_AGC_DEFAULT,           /* original configuration */
        TDA10046_AGC_IFO_AUTO_NEG,      /* IF AGC only, automatic, negtive */
        TDA10046_AGC_IFO_AUTO_POS,      /* IF AGC only, automatic, positive */
-       TDA10046_AGC_TDA827X,       /* IF AGC only, special setup for tda827x */
+       TDA10046_AGC_TDA827X,           /* IF AGC only, special setup for tda827x */
+       TDA10046_AGC_TDA827X_GPL,       /* same as above, but GPIOs 0 */
 };
 
 enum tda10046_if {
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
new file mode 100644 (file)
index 0000000..d7d9f59
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "zl10353_priv.h"
+#include "zl10353.h"
+
+struct zl10353_state {
+       struct i2c_adapter *i2c;
+       struct dvb_frontend frontend;
+       struct dvb_frontend_ops ops;
+
+       struct zl10353_config config;
+};
+
+static int debug_regs = 0;
+
+static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+       u8 buf[2] = { reg, val };
+       struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0,
+                              .buf = buf, .len = 2 };
+       int err = i2c_transfer(state->i2c, &msg, 1);
+       if (err != 1) {
+               printk("zl10353: write to reg %x failed (err = %d)!\n", reg, err);
+               return err;
+       }
+       return 0;
+}
+
+int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+{
+       int err, i;
+       for (i = 0; i < ilen - 1; i++)
+               if ((err = zl10353_single_write(fe, ibuf[0] + i, ibuf[i + 1])))
+                       return err;
+
+       return 0;
+}
+
+static int zl10353_read_register(struct zl10353_state *state, u8 reg)
+{
+       int ret;
+       u8 b0[1] = { reg };
+       u8 b1[1] = { 0 };
+       struct i2c_msg msg[2] = { { .addr = state->config.demod_address,
+                                   .flags = 0,
+                                   .buf = b0, .len = 1 },
+                                 { .addr = state->config.demod_address,
+                                   .flags = I2C_M_RD,
+                                   .buf = b1, .len = 1 } };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2) {
+               printk("%s: readreg error (reg=%d, ret==%i)\n",
+                      __FUNCTION__, reg, ret);
+               return ret;
+       }
+
+       return b1[0];
+}
+
+static void zl10353_dump_regs(struct dvb_frontend *fe)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+       char buf[52], buf2[4];
+       int ret;
+       u8 reg;
+
+       /* Dump all registers. */
+       for (reg = 0; ; reg++) {
+               if (reg % 16 == 0) {
+                       if (reg)
+                               printk(KERN_DEBUG "%s\n", buf);
+                       sprintf(buf, "%02x: ", reg);
+               }
+               ret = zl10353_read_register(state, reg);
+               if (ret >= 0)
+                       sprintf(buf2, "%02x ", (u8)ret);
+               else
+                       strcpy(buf2, "-- ");
+               strcat(buf, buf2);
+               if (reg == 0xff)
+                       break;
+       }
+       printk(KERN_DEBUG "%s\n", buf);
+}
+
+static int zl10353_sleep(struct dvb_frontend *fe)
+{
+       static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
+
+       zl10353_write(fe, zl10353_softdown, sizeof(zl10353_softdown));
+       return 0;
+}
+
+static int zl10353_set_parameters(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *param)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+       u8 pllbuf[6] = { 0x67 };
+
+       /* These settings set "auto-everything" and start the FSM. */
+       zl10353_single_write(fe, 0x55, 0x80);
+       udelay(200);
+       zl10353_single_write(fe, 0xEA, 0x01);
+       udelay(200);
+       zl10353_single_write(fe, 0xEA, 0x00);
+
+       zl10353_single_write(fe, 0x56, 0x28);
+       zl10353_single_write(fe, 0x89, 0x20);
+       zl10353_single_write(fe, 0x5E, 0x00);
+       zl10353_single_write(fe, 0x65, 0x5A);
+       zl10353_single_write(fe, 0x66, 0xE9);
+       zl10353_single_write(fe, 0x62, 0x0A);
+
+       state->config.pll_set(fe, param, pllbuf + 1);
+       zl10353_write(fe, pllbuf, sizeof(pllbuf));
+
+       zl10353_single_write(fe, 0x70, 0x01);
+       udelay(250);
+       zl10353_single_write(fe, 0xE4, 0x00);
+       zl10353_single_write(fe, 0xE5, 0x2A);
+       zl10353_single_write(fe, 0xE9, 0x02);
+       zl10353_single_write(fe, 0xE7, 0x40);
+       zl10353_single_write(fe, 0xE8, 0x10);
+
+       return 0;
+}
+
+static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+       int s6, s7, s8;
+
+       if ((s6 = zl10353_read_register(state, STATUS_6)) < 0)
+               return -EREMOTEIO;
+       if ((s7 = zl10353_read_register(state, STATUS_7)) < 0)
+               return -EREMOTEIO;
+       if ((s8 = zl10353_read_register(state, STATUS_8)) < 0)
+               return -EREMOTEIO;
+
+       *status = 0;
+       if (s6 & (1 << 2))
+               *status |= FE_HAS_CARRIER;
+       if (s6 & (1 << 1))
+               *status |= FE_HAS_VITERBI;
+       if (s6 & (1 << 5))
+               *status |= FE_HAS_LOCK;
+       if (s7 & (1 << 4))
+               *status |= FE_HAS_SYNC;
+       if (s8 & (1 << 6))
+               *status |= FE_HAS_SIGNAL;
+
+       if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+           (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+               *status &= ~FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+       u8 _snr;
+
+       if (debug_regs)
+               zl10353_dump_regs(fe);
+
+       _snr = zl10353_read_register(state, SNR);
+       *snr = (_snr << 8) | _snr;
+
+       return 0;
+}
+
+static int zl10353_get_tune_settings(struct dvb_frontend *fe,
+                                    struct dvb_frontend_tune_settings
+                                        *fe_tune_settings)
+{
+       fe_tune_settings->min_delay_ms = 1000;
+       fe_tune_settings->step_size = 0;
+       fe_tune_settings->max_drift = 0;
+
+       return 0;
+}
+
+static int zl10353_init(struct dvb_frontend *fe)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+       u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F };
+       int rc = 0;
+
+       if (debug_regs)
+               zl10353_dump_regs(fe);
+
+       /* Do a "hard" reset if not already done */
+       if (zl10353_read_register(state, 0x50) != 0x03) {
+               rc = zl10353_write(fe, zl10353_reset_attach,
+                                  sizeof(zl10353_reset_attach));
+               if (debug_regs)
+                       zl10353_dump_regs(fe);
+       }
+
+       return 0;
+}
+
+static void zl10353_release(struct dvb_frontend *fe)
+{
+       struct zl10353_state *state = fe->demodulator_priv;
+
+       kfree(state);
+}
+
+static struct dvb_frontend_ops zl10353_ops;
+
+struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct zl10353_state *state = NULL;
+
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct zl10353_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->i2c = i2c;
+       memcpy(&state->config, config, sizeof(struct zl10353_config));
+       memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
+
+       /* check if the demod is there */
+       if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
+               goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+
+       return &state->frontend;
+error:
+       kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops zl10353_ops = {
+
+       .info = {
+               .name                   = "Zarlink ZL10353 DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 174000000,
+               .frequency_max          = 862000000,
+               .frequency_stepsize     = 166667,
+               .frequency_tolerance    = 0,
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+                       FE_CAN_MUTE_TS
+       },
+
+       .release = zl10353_release,
+
+       .init = zl10353_init,
+       .sleep = zl10353_sleep,
+
+       .set_frontend = zl10353_set_parameters,
+       .get_tune_settings = zl10353_get_tune_settings,
+
+       .read_status = zl10353_read_status,
+       .read_snr = zl10353_read_snr,
+};
+
+module_param(debug_regs, int, 0644);
+MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
+
+MODULE_DESCRIPTION("Zarlink ZL10353 DVB-T demodulator driver");
+MODULE_AUTHOR("Chris Pascoe");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(zl10353_attach);
+EXPORT_SYMBOL(zl10353_write);
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
new file mode 100644 (file)
index 0000000..5cc4ae7
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *  Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ZL10353_H
+#define ZL10353_H
+
+#include <linux/dvb/frontend.h>
+
+struct zl10353_config
+{
+       /* demodulator's I2C address */
+       u8 demod_address;
+
+       /* function which configures the PLL buffer (for secondary I2C
+        * connected tuner) or tunes the PLL (for direct connected tuner) */
+       int (*pll_set)(struct dvb_frontend *fe,
+                      struct dvb_frontend_parameters *params, u8 *pllbuf);
+};
+
+extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
+                                          struct i2c_adapter *i2c);
+
+extern int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen);
+
+#endif /* ZL10353_H */
diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
new file mode 100644 (file)
index 0000000..b72224b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  Driver for Zarlink DVB-T ZL10353 demodulator
+ *
+ *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef _ZL10353_PRIV_
+#define _ZL10353_PRIV_
+
+#define ID_ZL10353     0x14
+
+enum zl10353_reg_addr {
+       INTERRUPT_0     = 0x00,
+       INTERRUPT_1     = 0x01,
+       INTERRUPT_2     = 0x02,
+       INTERRUPT_3     = 0x03,
+       INTERRUPT_4     = 0x04,
+       INTERRUPT_5     = 0x05,
+       STATUS_6        = 0x06,
+       STATUS_7        = 0x07,
+       STATUS_8        = 0x08,
+       STATUS_9        = 0x09,
+       SNR             = 0x10,
+       CHIP_ID         = 0x7F,
+};
+
+#endif                          /* _ZL10353_PRIV_ */
index 7c6ccb9..840efec 100644 (file)
@@ -54,7 +54,6 @@
 #include <linux/i2c.h>
 
 #include <asm/system.h>
-#include <asm/semaphore.h>
 
 #include <linux/dvb/frontend.h>
 
 #include "av7110_ca.h"
 #include "av7110_ipack.h"
 
+#include "bsbe1.h"
+#include "lnbp21.h"
+#include "bsru6.h"
+
 #define TS_WIDTH  376
 #define TS_HEIGHT 512
 #define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
@@ -82,6 +85,8 @@ static int hw_sections;
 static int rgb_on;
 static int volume = 255;
 static int budgetpatch;
+static int wss_cfg_4_3 = 0x4008;
+static int wss_cfg_16_9 = 0x0007;
 
 module_param_named(debug, av7110_debug, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
@@ -100,6 +105,10 @@ module_param(volume, int, 0444);
 MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
 module_param(budgetpatch, int, 0444);
 MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
+module_param(wss_cfg_4_3, int, 0444);
+MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
+module_param(wss_cfg_16_9, int, 0444);
+MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data");
 
 static void restart_feeds(struct av7110 *av7110);
 
@@ -125,6 +134,13 @@ static void init_av7110_av(struct av7110 *av7110)
        if (ret < 0)
                printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
 
+       ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
+       if (ret < 0)
+               printk("dvb-ttpci: unable to configure 4:3 wss\n");
+       ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9);
+       if (ret < 0)
+               printk("dvb-ttpci: unable to configure 16:9 wss\n");
+
        ret = av7710_set_video_mode(av7110, vidmode);
        if (ret < 0)
                printk("dvb-ttpci:cannot set video mode:%d\n",ret);
@@ -242,10 +258,10 @@ static int arm_thread(void *data)
                if (!av7110->arm_ready)
                        continue;
 
-               if (down_interruptible(&av7110->dcomlock))
+               if (mutex_lock_interruptible(&av7110->dcomlock))
                        break;
                newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
-               up(&av7110->dcomlock);
+               mutex_unlock(&av7110->dcomlock);
 
                if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
                        printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
@@ -253,10 +269,10 @@ static int arm_thread(void *data)
 
                        recover_arm(av7110);
 
-                       if (down_interruptible(&av7110->dcomlock))
+                       if (mutex_lock_interruptible(&av7110->dcomlock))
                                break;
                        newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
-                       up(&av7110->dcomlock);
+                       mutex_unlock(&av7110->dcomlock);
                }
                av7110->arm_loops = newloops;
                av7110->arm_errors = 0;
@@ -741,7 +757,7 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
        int ret = 0;
        dprintk(4, "%p\n", av7110);
 
-       if (down_interruptible(&av7110->pid_mutex))
+       if (mutex_lock_interruptible(&av7110->pid_mutex))
                return -ERESTARTSYS;
 
        if (!(vpid & 0x8000))
@@ -760,7 +776,7 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
                ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
        }
 
-       up(&av7110->pid_mutex);
+       mutex_unlock(&av7110->pid_mutex);
        return ret;
 }
 
@@ -1088,11 +1104,9 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
        struct av7110 *av7110;
 
        /* pointer casting paranoia... */
-       if (!demux)
-               BUG();
+       BUG_ON(!demux);
        dvbdemux = (struct dvb_demux *) demux->priv;
-       if (!dvbdemux)
-               BUG();
+       BUG_ON(!dvbdemux);
        av7110 = (struct av7110 *) dvbdemux->priv;
 
        dprintk(4, "%p\n", av7110);
@@ -1570,208 +1584,6 @@ static struct ves1x93_config alps_bsrv2_config = {
        .pll_set = alps_bsrv2_pll_set,
 };
 
-
-static u8 alps_bsru6_inittab[] = {
-       0x01, 0x15,
-       0x02, 0x30,
-       0x03, 0x00,
-       0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-       0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-       0x06, 0x40,   /* DAC not used, set to high impendance mode */
-       0x07, 0x00,   /* DAC LSB */
-       0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-       0x09, 0x00,   /* FIFO */
-       0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-       0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-       0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-       0x10, 0x3f,   // AGC2  0x3d
-       0x11, 0x84,
-       0x12, 0xb9,
-       0x15, 0xc9,   // lock detector threshold
-       0x16, 0x00,
-       0x17, 0x00,
-       0x18, 0x00,
-       0x19, 0x00,
-       0x1a, 0x00,
-       0x1f, 0x50,
-       0x20, 0x00,
-       0x21, 0x00,
-       0x22, 0x00,
-       0x23, 0x00,
-       0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-       0x29, 0x1e,  // 1/2 threshold
-       0x2a, 0x14,  // 2/3 threshold
-       0x2b, 0x0f,  // 3/4 threshold
-       0x2c, 0x09,  // 5/6 threshold
-       0x2d, 0x05,  // 7/8 threshold
-       0x2e, 0x01,
-       0x31, 0x1f,  // test all FECs
-       0x32, 0x19,  // viterbi and synchro search
-       0x33, 0xfc,  // rs control
-       0x34, 0x93,  // error control
-       0x0f, 0x52,
-       0xff, 0xff
-};
-
-static int alps_bsru6_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 alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-       int ret;
-       u8 data[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
-               return -EINVAL;
-
-       div = (params->frequency + (125 - 1)) / 125; // round correctly
-       data[0] = (div >> 8) & 0x7f;
-       data[1] = div & 0xff;
-       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-       data[3] = 0xC4;
-
-       if (params->frequency > 1530000) data[3] = 0xc0;
-
-       ret = i2c_transfer(i2c, &msg, 1);
-       if (ret != 1)
-               return -EIO;
-       return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
-       .demod_address = 0x68,
-       .inittab = alps_bsru6_inittab,
-       .mclk = 88000000UL,
-       .invert = 1,
-       .skip_reinit = 0,
-       .lock_output = STV0229_LOCKOUTPUT_1,
-       .volt13_op0_op1 = STV0299_VOLT13_OP1,
-       .min_delay_ms = 100,
-       .set_symbol_rate = alps_bsru6_set_symbol_rate,
-       .pll_set = alps_bsru6_pll_set,
-};
-
-
-static u8 alps_bsbe1_inittab[] = {
-       0x01, 0x15,
-       0x02, 0x30,
-       0x03, 0x00,
-       0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-       0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-       0x06, 0x40,   /* DAC not used, set to high impendance mode */
-       0x07, 0x00,   /* DAC LSB */
-       0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-       0x09, 0x00,   /* FIFO */
-       0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-       0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-       0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-       0x10, 0x3f,   // AGC2  0x3d
-       0x11, 0x84,
-       0x12, 0xb9,
-       0x15, 0xc9,   // lock detector threshold
-       0x16, 0x00,
-       0x17, 0x00,
-       0x18, 0x00,
-       0x19, 0x00,
-       0x1a, 0x00,
-       0x1f, 0x50,
-       0x20, 0x00,
-       0x21, 0x00,
-       0x22, 0x00,
-       0x23, 0x00,
-       0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-       0x29, 0x1e,  // 1/2 threshold
-       0x2a, 0x14,  // 2/3 threshold
-       0x2b, 0x0f,  // 3/4 threshold
-       0x2c, 0x09,  // 5/6 threshold
-       0x2d, 0x05,  // 7/8 threshold
-       0x2e, 0x01,
-       0x31, 0x1f,  // test all FECs
-       0x32, 0x19,  // viterbi and synchro search
-       0x33, 0xfc,  // rs control
-       0x34, 0x93,  // error control
-       0x0f, 0x92,
-       0xff, 0xff
-};
-
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-       int ret;
-       u8 data[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
-               return -EINVAL;
-
-       div = (params->frequency + (125 - 1)) / 125; // round correctly
-       data[0] = (div >> 8) & 0x7f;
-       data[1] = div & 0xff;
-       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-       data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
-
-       ret = i2c_transfer(i2c, &msg, 1);
-       return (ret != 1) ? -EIO : 0;
-}
-
-static struct stv0299_config alps_bsbe1_config = {
-       .demod_address = 0x68,
-       .inittab = alps_bsbe1_inittab,
-       .mclk = 88000000UL,
-       .invert = 1,
-       .skip_reinit = 0,
-       .min_delay_ms = 100,
-       .set_symbol_rate = alps_bsru6_set_symbol_rate,
-       .pll_set = alps_bsbe1_pll_set,
-};
-
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-       struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
-       int ret;
-       u8 data[1];
-       struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
-
-       switch(voltage) {
-       case SEC_VOLTAGE_OFF:
-               data[0] = 0x00;
-               break;
-       case SEC_VOLTAGE_13:
-               data[0] = 0x44;
-               break;
-       case SEC_VOLTAGE_18:
-               data[0] = 0x4c;
-               break;
-       default:
-               return -EINVAL;
-       };
-
-       ret = i2c_transfer(&av7110->i2c_adap, &msg, 1);
-       return (ret != 1) ? -EIO : 0;
-}
-
-
 static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct av7110* av7110 = fe->dvb->priv;
@@ -2096,7 +1908,7 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
        if (av7110->playing)
                return 0;
 
-       if (down_interruptible(&av7110->pid_mutex))
+       if (mutex_lock_interruptible(&av7110->pid_mutex))
                return -ERESTARTSYS;
 
        if (synced) {
@@ -2118,7 +1930,7 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
        if (!ret)
                av7110->fe_synced = synced;
 
-       up(&av7110->pid_mutex);
+       mutex_unlock(&av7110->pid_mutex);
        return ret;
 }
 
@@ -2374,9 +2186,15 @@ static int frontend_init(struct av7110 *av7110)
                        /* ALPS BSBE1 */
                        av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
                        if (av7110->fe) {
-                               av7110->fe->ops->set_voltage = lnbp21_set_voltage;
-                               av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
-                               av7110->recover = dvb_s_recover;
+                               if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+                                       printk("dvb-ttpci: LNBP21 not found!\n");
+                                       if (av7110->fe->ops->release)
+                                               av7110->fe->ops->release(av7110->fe);
+                                       av7110->fe = NULL;
+                               } else {
+                                       av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+                                       av7110->recover = dvb_s_recover;
+                               }
                        }
                        break;
                }
@@ -2714,16 +2532,16 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
        tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
        tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
 
-       sema_init(&av7110->pid_mutex, 1);
+       mutex_init(&av7110->pid_mutex);
 
        /* locks for data transfers from/to AV7110 */
        spin_lock_init(&av7110->debilock);
-       sema_init(&av7110->dcomlock, 1);
+       mutex_init(&av7110->dcomlock);
        av7110->debitype = -1;
 
        /* default OSD window */
        av7110->osdwin = 1;
-       sema_init(&av7110->osd_sema, 1);
+       mutex_init(&av7110->osd_mutex);
 
        /* ARM "watchdog" */
        init_waitqueue_head(&av7110->arm_wait);
index fafd25f..3e2e121 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/dvb/ca.h>
 #include <linux/dvb/osd.h>
 #include <linux/dvb/net.h>
+#include <linux/mutex.h>
 
 #include "dvbdev.h"
 #include "demux.h"
@@ -127,7 +128,7 @@ struct av7110 {
        /* DEBI and polled command interface */
 
        spinlock_t              debilock;
-       struct semaphore        dcomlock;
+       struct mutex            dcomlock;
        volatile int            debitype;
        volatile int            debilen;
 
@@ -146,7 +147,7 @@ struct av7110 {
 
        int                     osdwin;      /* currently active window */
        u16                     osdbpp[8];
-       struct semaphore        osd_sema;
+       struct mutex            osd_mutex;
 
        /* CA */
 
@@ -172,7 +173,7 @@ struct av7110 {
        struct tasklet_struct   vpe_tasklet;
 
        int                     fe_synced;
-       struct semaphore        pid_mutex;
+       struct mutex            pid_mutex;
 
        int                     video_blank;
        struct video_status     videostate;
index 0bb6e74..75736f2 100644 (file)
@@ -327,10 +327,10 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
        start = jiffies;
        for (;;) {
                err = time_after(jiffies, start + ARM_WAIT_FREE);
-               if (down_interruptible(&av7110->dcomlock))
+               if (mutex_lock_interruptible(&av7110->dcomlock))
                        return -ERESTARTSYS;
                stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
-               up(&av7110->dcomlock);
+               mutex_unlock(&av7110->dcomlock);
                if ((stat & flags) == 0)
                        break;
                if (err) {
@@ -487,11 +487,11 @@ static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
                dprintk(1, "arm not ready.\n");
                return -1;
        }
-       if (down_interruptible(&av7110->dcomlock))
+       if (mutex_lock_interruptible(&av7110->dcomlock))
                return -ERESTARTSYS;
 
        ret = __av7110_send_fw_cmd(av7110, buf, length);
-       up(&av7110->dcomlock);
+       mutex_unlock(&av7110->dcomlock);
        if (ret && ret!=-ERESTARTSYS)
                printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
                       __FUNCTION__, ret);
@@ -563,11 +563,11 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
                return -1;
        }
 
-       if (down_interruptible(&av7110->dcomlock))
+       if (mutex_lock_interruptible(&av7110->dcomlock))
                return -ERESTARTSYS;
 
        if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
-               up(&av7110->dcomlock);
+               mutex_unlock(&av7110->dcomlock);
                printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
                return err;
        }
@@ -579,7 +579,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
                        break;
                if (err) {
                        printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
-                       up(&av7110->dcomlock);
+                       mutex_unlock(&av7110->dcomlock);
                        return -ETIMEDOUT;
                }
 #ifdef _NOHANDSHAKE
@@ -595,7 +595,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
                        break;
                if (err) {
                        printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
-                       up(&av7110->dcomlock);
+                       mutex_unlock(&av7110->dcomlock);
                        return -ETIMEDOUT;
                }
                msleep(1);
@@ -606,12 +606,12 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
        stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
        if (stat & GPMQOver) {
                printk(KERN_ERR "%s: GPMQOver\n", __FUNCTION__);
-               up(&av7110->dcomlock);
+               mutex_unlock(&av7110->dcomlock);
                return -1;
        }
        else if (stat & OSDQOver) {
                printk(KERN_ERR "%s: OSDQOver\n", __FUNCTION__);
-               up(&av7110->dcomlock);
+               mutex_unlock(&av7110->dcomlock);
                return -1;
        }
 #endif
@@ -619,7 +619,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
        for (i = 0; i < reply_buf_len; i++)
                reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
 
-       up(&av7110->dcomlock);
+       mutex_unlock(&av7110->dcomlock);
        return 0;
 }
 
@@ -735,7 +735,7 @@ static int FlushText(struct av7110 *av7110)
        unsigned long start;
        int err;
 
-       if (down_interruptible(&av7110->dcomlock))
+       if (mutex_lock_interruptible(&av7110->dcomlock))
                return -ERESTARTSYS;
        start = jiffies;
        while (1) {
@@ -745,12 +745,12 @@ static int FlushText(struct av7110 *av7110)
                if (err) {
                        printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
                               __FUNCTION__);
-                       up(&av7110->dcomlock);
+                       mutex_unlock(&av7110->dcomlock);
                        return -ETIMEDOUT;
                }
                msleep(1);
        }
-       up(&av7110->dcomlock);
+       mutex_unlock(&av7110->dcomlock);
        return 0;
 }
 
@@ -761,7 +761,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
        int length = strlen(buf) + 1;
        u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
 
-       if (down_interruptible(&av7110->dcomlock))
+       if (mutex_lock_interruptible(&av7110->dcomlock))
                return -ERESTARTSYS;
 
        start = jiffies;
@@ -772,7 +772,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
                if (ret) {
                        printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
                               __FUNCTION__);
-                       up(&av7110->dcomlock);
+                       mutex_unlock(&av7110->dcomlock);
                        return -ETIMEDOUT;
                }
                msleep(1);
@@ -786,7 +786,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
                if (ret) {
                        printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
                               __FUNCTION__);
-                       up(&av7110->dcomlock);
+                       mutex_unlock(&av7110->dcomlock);
                        return -ETIMEDOUT;
                }
                msleep(1);
@@ -798,7 +798,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
        if (length & 1)
                wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
        ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
-       up(&av7110->dcomlock);
+       mutex_unlock(&av7110->dcomlock);
        if (ret && ret!=-ERESTARTSYS)
                printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
        return ret;
@@ -1062,7 +1062,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
 {
        int ret;
 
-       if (down_interruptible(&av7110->osd_sema))
+       if (mutex_lock_interruptible(&av7110->osd_mutex))
                return -ERESTARTSYS;
 
        switch (dc->cmd) {
@@ -1198,7 +1198,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
                break;
        }
 
-       up(&av7110->osd_sema);
+       mutex_unlock(&av7110->osd_mutex);
        if (ret==-ERESTARTSYS)
                dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
        else if (ret)
index 94cf38c..2f23cea 100644 (file)
@@ -579,14 +579,11 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size
                return -EFAULT;
        if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
                return -EINVAL;
-       if (d.id) {
+       if (d.id)
                av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
-               rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig,
-                                  2, 1, av7110->wssData);
-       } else {
-               av7110->wssData = 0;
-               rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
-       }
+       else
+               av7110->wssData = 0x8000;
+       rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
        return (rc < 0) ? rc : count;
 }
 
index 1465c04..9dd4745 100644 (file)
@@ -1000,6 +1000,7 @@ static u8 read_pwm(struct budget_av *budget_av)
 
 #define SUBID_DVBS_TV_STAR     0x0014
 #define SUBID_DVBS_TV_STAR_CI  0x0016
+#define SUBID_DVBS_EASYWATCH   0x001e
 #define SUBID_DVBC_KNC1                0x0020
 #define SUBID_DVBC_KNC1_PLUS   0x0021
 #define SUBID_DVBC_CINERGY1200 0x1156
@@ -1038,6 +1039,7 @@ static void frontend_init(struct budget_av *budget_av)
        case SUBID_DVBS_TV_STAR:
        case SUBID_DVBS_TV_STAR_CI:
        case SUBID_DVBS_CYNERGY1200N:
+       case SUBID_DVBS_EASYWATCH:
                fe = stv0299_attach(&philips_sd1878_config,
                                &budget_av->budget.i2c_adap);
                break;
@@ -1285,6 +1287,7 @@ MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
 MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1300,6 +1303,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
+       MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
        MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
        MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
        MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
index b9b3cd9..5f91036 100644 (file)
@@ -42,6 +42,9 @@
 #include "stv0299.h"
 #include "stv0297.h"
 #include "tda1004x.h"
+#include "lnbp21.h"
+#include "bsbe1.h"
+#include "bsru6.h"
 
 #define DEBIADDR_IR            0x1234
 #define DEBIADDR_CICONTROL     0x0000
@@ -474,123 +477,6 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
                tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
 }
 
-
-static u8 alps_bsru6_inittab[] = {
-       0x01, 0x15,
-       0x02, 0x00,
-       0x03, 0x00,
-       0x04, 0x7d,             /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-       0x05, 0x35,             /* I2CT = 0, SCLT = 1, SDAT = 1 */
-       0x06, 0x40,             /* DAC not used, set to high impendance mode */
-       0x07, 0x00,             /* DAC LSB */
-       0x08, 0x40,             /* DiSEqC off, LNB power on OP2/LOCK pin on */
-       0x09, 0x00,             /* FIFO */
-       0x0c, 0x51,             /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-       0x0d, 0x82,             /* DC offset compensation = ON, beta_agc1 = 2 */
-       0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
-       0x10, 0x3f,             // AGC2  0x3d
-       0x11, 0x84,
-       0x12, 0xb9,
-       0x15, 0xc9,             // lock detector threshold
-       0x16, 0x00,
-       0x17, 0x00,
-       0x18, 0x00,
-       0x19, 0x00,
-       0x1a, 0x00,
-       0x1f, 0x50,
-       0x20, 0x00,
-       0x21, 0x00,
-       0x22, 0x00,
-       0x23, 0x00,
-       0x28, 0x00,             // out imp: normal  out type: parallel FEC mode:0
-       0x29, 0x1e,             // 1/2 threshold
-       0x2a, 0x14,             // 2/3 threshold
-       0x2b, 0x0f,             // 3/4 threshold
-       0x2c, 0x09,             // 5/6 threshold
-       0x2d, 0x05,             // 7/8 threshold
-       0x2e, 0x01,
-       0x31, 0x1f,             // test all FECs
-       0x32, 0x19,             // viterbi and synchro search
-       0x33, 0xfc,             // rs control
-       0x34, 0x93,             // error control
-       0x0f, 0x52,
-       0xff, 0xff
-};
-
-static int alps_bsru6_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 alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
-{
-       u8 buf[4];
-       u32 div;
-       struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
-
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
-               return -EINVAL;
-
-       div = (params->frequency + (125 - 1)) / 125;    // round correctly
-       buf[0] = (div >> 8) & 0x7f;
-       buf[1] = div & 0xff;
-       buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-       buf[3] = 0xC4;
-
-       if (params->frequency > 1530000)
-               buf[3] = 0xc0;
-
-       if (i2c_transfer(i2c, &msg, 1) != 1)
-               return -EIO;
-       return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
-       .demod_address = 0x68,
-       .inittab = alps_bsru6_inittab,
-       .mclk = 88000000UL,
-       .invert = 1,
-       .skip_reinit = 0,
-       .lock_output = STV0229_LOCKOUTPUT_1,
-       .volt13_op0_op1 = STV0299_VOLT13_OP1,
-       .min_delay_ms = 100,
-       .set_symbol_rate = alps_bsru6_set_symbol_rate,
-       .pll_set = alps_bsru6_pll_set,
-};
-
-
-
-
 static u8 philips_su1278_tt_inittab[] = {
        0x01, 0x0f,
        0x02, 0x30,
@@ -1069,6 +955,20 @@ static void frontend_init(struct budget_ci *budget_ci)
                        break;
                }
                break;
+
+       case 0x1017:            // TT S-1500 PCI
+               budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
+               if (budget_ci->budget.dvb_frontend) {
+                       budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+                       if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+                               printk("%s: No LNBP21 found!\n", __FUNCTION__);
+                               if (budget_ci->budget.dvb_frontend->ops->release)
+                                       budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+                               budget_ci->budget.dvb_frontend = NULL;
+                       }
+               }
+
+               break;
        }
 
        if (budget_ci->budget.dvb_frontend == NULL) {
@@ -1146,6 +1046,7 @@ static int budget_ci_detach(struct saa7146_dev *dev)
 
 static struct saa7146_extension budget_extension;
 
+MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T         PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
@@ -1157,6 +1058,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
        MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
        MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
+       MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
        {
         .vendor = 0,
         }
index fc416cf..9fc9185 100644 (file)
@@ -37,6 +37,8 @@
 #include "ves1x93.h"
 #include "tda8083.h"
 
+#include "bsru6.h"
+
 #define budget_patch budget
 
 static struct saa7146_extension budget_extension;
@@ -290,103 +292,6 @@ static struct ves1x93_config alps_bsrv2_config = {
        .pll_set = alps_bsrv2_pll_set,
 };
 
-static u8 alps_bsru6_inittab[] = {
-       0x01, 0x15,
-       0x02, 0x00,
-       0x03, 0x00,
-       0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-       0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-       0x06, 0x40,   /* DAC not used, set to high impendance mode */
-       0x07, 0x00,   /* DAC LSB */
-       0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-       0x09, 0x00,   /* FIFO */
-       0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-       0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-       0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-       0x10, 0x3f,   // AGC2  0x3d
-       0x11, 0x84,
-       0x12, 0xb9,
-       0x15, 0xc9,   // lock detector threshold
-       0x16, 0x00,
-       0x17, 0x00,
-       0x18, 0x00,
-       0x19, 0x00,
-       0x1a, 0x00,
-       0x1f, 0x50,
-       0x20, 0x00,
-       0x21, 0x00,
-       0x22, 0x00,
-       0x23, 0x00,
-       0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-       0x29, 0x1e,  // 1/2 threshold
-       0x2a, 0x14,  // 2/3 threshold
-       0x2b, 0x0f,  // 3/4 threshold
-       0x2c, 0x09,  // 5/6 threshold
-       0x2d, 0x05,  // 7/8 threshold
-       0x2e, 0x01,
-       0x31, 0x1f,  // test all FECs
-       0x32, 0x19,  // viterbi and synchro search
-       0x33, 0xfc,  // rs control
-       0x34, 0x93,  // error control
-       0x0f, 0x52,
-       0xff, 0xff
-};
-
-static int alps_bsru6_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 alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-       u8 data[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-       if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
-
-       div = (params->frequency + (125 - 1)) / 125; // round correctly
-       data[0] = (div >> 8) & 0x7f;
-       data[1] = div & 0xff;
-       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-       data[3] = 0xC4;
-
-       if (params->frequency > 1530000) data[3] = 0xc0;
-
-       if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO;
-       return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
-       .demod_address = 0x68,
-       .inittab = alps_bsru6_inittab,
-       .mclk = 88000000UL,
-       .invert = 1,
-       .skip_reinit = 0,
-       .lock_output = STV0229_LOCKOUTPUT_1,
-       .volt13_op0_op1 = STV0299_VOLT13_OP1,
-       .min_delay_ms = 100,
-       .set_symbol_rate = alps_bsru6_set_symbol_rate,
-       .pll_set = alps_bsru6_pll_set,
-};
-
 static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
index 238c77b..c23c02d 100644 (file)
@@ -41,6 +41,8 @@
 #include "l64781.h"
 #include "tda8083.h"
 #include "s5h1420.h"
+#include "lnbp21.h"
+#include "bsru6.h"
 
 static void Set22K (struct budget *budget, int state)
 {
@@ -184,64 +186,6 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
        return 0;
 }
 
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
-       struct budget* budget = (struct budget*) fe->dvb->priv;
-       u8 buf;
-       struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
-
-       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-       switch(voltage) {
-       case SEC_VOLTAGE_13:
-               buf = (buf & 0xf7) | 0x04;
-               break;
-
-       case SEC_VOLTAGE_18:
-               buf = (buf & 0xf7) | 0x0c;
-               break;
-
-       case SEC_VOLTAGE_OFF:
-               buf = buf & 0xf0;
-               break;
-       }
-
-       msg.flags = 0;
-       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-       return 0;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg)
-{
-       struct budget* budget = (struct budget*) fe->dvb->priv;
-       u8 buf;
-       struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
-
-       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-       if (arg) {
-               buf = buf | 0x10;
-       } else {
-               buf = buf & 0xef;
-       }
-
-       msg.flags = 0;
-       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
-
-       return 0;
-}
-
-static int lnbp21_init(struct budget* budget)
-{
-       u8 buf = 0x00;
-       struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
-
-       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
-               return -EIO;
-       return 0;
-}
-
 static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -277,176 +221,6 @@ static struct ves1x93_config alps_bsrv2_config =
        .pll_set = alps_bsrv2_pll_set,
 };
 
-static u8 alps_bsru6_inittab[] = {
-       0x01, 0x15,
-       0x02, 0x00,
-       0x03, 0x00,
-       0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-       0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
-       0x06, 0x40,   /* DAC not used, set to high impendance mode */
-       0x07, 0x00,   /* DAC LSB */
-       0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
-       0x09, 0x00,   /* FIFO */
-       0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-       0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
-       0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
-       0x10, 0x3f,   // AGC2  0x3d
-       0x11, 0x84,
-       0x12, 0xb9,
-       0x15, 0xc9,   // lock detector threshold
-       0x16, 0x00,
-       0x17, 0x00,
-       0x18, 0x00,
-       0x19, 0x00,
-       0x1a, 0x00,
-       0x1f, 0x50,
-       0x20, 0x00,
-       0x21, 0x00,
-       0x22, 0x00,
-       0x23, 0x00,
-       0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
-       0x29, 0x1e,  // 1/2 threshold
-       0x2a, 0x14,  // 2/3 threshold
-       0x2b, 0x0f,  // 3/4 threshold
-       0x2c, 0x09,  // 5/6 threshold
-       0x2d, 0x05,  // 7/8 threshold
-       0x2e, 0x01,
-       0x31, 0x1f,  // test all FECs
-       0x32, 0x19,  // viterbi and synchro search
-       0x33, 0xfc,  // rs control
-       0x34, 0x93,  // error control
-       0x0f, 0x52,
-       0xff, 0xff
-};
-
-static int alps_bsru6_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 alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-       u8 data[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-       if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
-
-       div = (params->frequency + (125 - 1)) / 125; // round correctly
-       data[0] = (div >> 8) & 0x7f;
-       data[1] = div & 0xff;
-       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-       data[3] = 0xC4;
-
-       if (params->frequency > 1530000) data[3] = 0xc0;
-
-       if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO;
-       return 0;
-}
-
-static struct stv0299_config alps_bsru6_config = {
-
-       .demod_address = 0x68,
-       .inittab = alps_bsru6_inittab,
-       .mclk = 88000000UL,
-       .invert = 1,
-       .skip_reinit = 0,
-       .lock_output = STV0229_LOCKOUTPUT_1,
-       .volt13_op0_op1 = STV0299_VOLT13_OP1,
-       .min_delay_ms = 100,
-       .set_symbol_rate = alps_bsru6_set_symbol_rate,
-       .pll_set = alps_bsru6_pll_set,
-};
-
-static u8 alps_bsbe1_inittab[] = {
-       0x01, 0x15,
-       0x02, 0x30,
-       0x03, 0x00,
-       0x04, 0x7d,  /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
-       0x05, 0x35,  /* I2CT = 0, SCLT = 1, SDAT = 1 */
-       0x06, 0x40,  /* DAC not used, set to high impendance mode */
-       0x07, 0x00,  /* DAC LSB */
-       0x08, 0x40,  /* DiSEqC off, LNB power on OP2/LOCK pin on */
-       0x09, 0x00,  /* FIFO */
-       0x0c, 0x51,  /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
-       0x0d, 0x82,  /* DC offset compensation = ON, beta_agc1 = 2 */
-       0x0e, 0x23,  /* alpha_tmg = 2, beta_tmg = 3 */
-       0x10, 0x3f,  // AGC2 0x3d
-       0x11, 0x84,
-       0x12, 0xb9,
-       0x15, 0xc9,  // lock detector threshold
-       0x16, 0x00,
-       0x17, 0x00,
-       0x18, 0x00,
-       0x19, 0x00,
-       0x1a, 0x00,
-       0x1f, 0x50,
-       0x20, 0x00,
-       0x21, 0x00,
-       0x22, 0x00,
-       0x23, 0x00,
-       0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
-       0x29, 0x1e, // 1/2 threshold
-       0x2a, 0x14, // 2/3 threshold
-       0x2b, 0x0f, // 3/4 threshold
-       0x2c, 0x09, // 5/6 threshold
-       0x2d, 0x05, // 7/8 threshold
-       0x2e, 0x01,
-       0x31, 0x1f, // test all FECs
-       0x32, 0x19, // viterbi and synchro search
-       0x33, 0xfc, // rs control
-       0x34, 0x93, // error control
-       0x0f, 0x92, // 0x80 = inverse AGC
-       0xff, 0xff
-};
-
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
-{
-       int ret;
-       u8 data[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
-               return -EINVAL;
-
-       div = (params->frequency + (125 - 1)) / 125; // round correctly
-       data[0] = (div >> 8) & 0x7f;
-       data[1] = div & 0xff;
-       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
-       data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
-
-       ret = i2c_transfer(i2c, &msg, 1);
-       return (ret != 1) ? -EIO : 0;
-}
-
-static struct stv0299_config alps_bsbe1_config = {
-       .demod_address = 0x68,
-       .inittab = alps_bsbe1_inittab,
-       .mclk = 88000000UL,
-       .invert = 1,
-       .skip_reinit = 0,
-       .min_delay_ms = 100,
-       .set_symbol_rate = alps_bsru6_set_symbol_rate,
-       .pll_set = alps_bsbe1_pll_set,
-};
-
 static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -580,20 +354,6 @@ static u8 read_pwm(struct budget* budget)
 static void frontend_init(struct budget *budget)
 {
        switch(budget->dev->pci->subsystem_device) {
-       case 0x1017:
-               // try the ALPS BSBE1 now
-               budget->dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget->i2c_adap);
-               if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
-                       budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-                       budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
-                       if (lnbp21_init(budget)) {
-                               printk("%s: No LNBP21 found!\n", __FUNCTION__);
-                               goto error_out;
-                       }
-               }
-
-               break;
        case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
        case 0x1013:
                // try the ALPS BSRV2 first of all
@@ -646,9 +406,7 @@ static void frontend_init(struct budget *budget)
        case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
                budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
                if (budget->dvb_frontend) {
-                       budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
-                       budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-                       if (lnbp21_init(budget)) {
+                       if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
                                printk("%s: No LNBP21 found!\n", __FUNCTION__);
                                goto error_out;
                        }
@@ -719,7 +477,6 @@ static int budget_detach (struct saa7146_dev* dev)
 
 static struct saa7146_extension budget_extension;
 
-MAKE_BUDGET_INFO(ttbs2, "TT-Budget/WinTV-NOVA-S PCI (rev AL/alps bsbe1 lnbp21 frontend)", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T  PCI",  BUDGET_TT);
@@ -732,7 +489,6 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
        MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
-       MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
        MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
        MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
        MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
index c7bb63c..4ac0f4d 100644 (file)
@@ -10,6 +10,8 @@
 #include "dvb_net.h"
 
 #include <linux/module.h>
+#include <linux/mutex.h>
+
 #include <media/saa7146.h>
 
 extern int budget_debug;
@@ -51,7 +53,7 @@ struct budget {
        struct dmx_frontend mem_frontend;
 
        int fe_synced;
-       struct semaphore pid_mutex;
+       struct mutex pid_mutex;
 
        int ci_present;
        int video_port;
index 5a13c47..248fdc7 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/jiffies.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "dvb_frontend.h"
 #include "dmxdev.h"
@@ -35,7 +35,6 @@
 #include <linux/dvb/dmx.h>
 #include <linux/pci.h>
 
-
 /*
   TTUSB_HWSECTIONS:
     the DSP supports filtering in hardware, however, since the "muxstream"
@@ -83,8 +82,8 @@ struct ttusb {
        struct dvb_net dvbnet;
 
        /* and one for USB access. */
-       struct semaphore semi2c;
-       struct semaphore semusb;
+       struct mutex semi2c;
+       struct mutex semusb;
 
        struct dvb_adapter adapter;
        struct usb_device *dev;
@@ -150,7 +149,7 @@ static int ttusb_cmd(struct ttusb *ttusb,
        printk("\n");
 #endif
 
-       if (down_interruptible(&ttusb->semusb) < 0)
+       if (mutex_lock_interruptible(&ttusb->semusb) < 0)
                return -EAGAIN;
 
        err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
@@ -158,13 +157,13 @@ static int ttusb_cmd(struct ttusb *ttusb,
        if (err != 0) {
                dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
                        __FUNCTION__, err);
-               up(&ttusb->semusb);
+               mutex_unlock(&ttusb->semusb);
                return err;
        }
        if (actual_len != len) {
                dprintk("%s: only wrote %d of %d bytes\n", __FUNCTION__,
                        actual_len, len);
-               up(&ttusb->semusb);
+               mutex_unlock(&ttusb->semusb);
                return -1;
        }
 
@@ -174,7 +173,7 @@ static int ttusb_cmd(struct ttusb *ttusb,
        if (err != 0) {
                printk("%s: failed, receive error %d\n", __FUNCTION__,
                       err);
-               up(&ttusb->semusb);
+               mutex_unlock(&ttusb->semusb);
                return err;
        }
 #if DEBUG >= 3
@@ -185,14 +184,14 @@ static int ttusb_cmd(struct ttusb *ttusb,
        printk("\n");
 #endif
        if (!needresult)
-               up(&ttusb->semusb);
+               mutex_unlock(&ttusb->semusb);
        return 0;
 }
 
 static int ttusb_result(struct ttusb *ttusb, u8 * data, int len)
 {
        memcpy(data, ttusb->last_result, len);
-       up(&ttusb->semusb);
+       mutex_unlock(&ttusb->semusb);
        return 0;
 }
 
@@ -250,7 +249,7 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num
        int i = 0;
        int inc;
 
-       if (down_interruptible(&ttusb->semi2c) < 0)
+       if (mutex_lock_interruptible(&ttusb->semi2c) < 0)
                return -EAGAIN;
 
        while (i < num) {
@@ -284,7 +283,7 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num
                i += inc;
        }
 
-       up(&ttusb->semi2c);
+       mutex_unlock(&ttusb->semi2c);
        return i;
 }
 
@@ -689,8 +688,7 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
                                memcpy(ttusb->muxpack + ttusb->muxpack_ptr,
                                       data, avail);
                                ttusb->muxpack_ptr += avail;
-                               if (ttusb->muxpack_ptr > 264)
-                                       BUG();
+                               BUG_ON(ttusb->muxpack_ptr > 264);
                                data += avail;
                                len -= avail;
                                /* determine length */
@@ -1495,8 +1493,11 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        ttusb->dev = udev;
        ttusb->c = 0;
        ttusb->mux_state = 0;
-       sema_init(&ttusb->semi2c, 0);
-       sema_init(&ttusb->semusb, 1);
+       mutex_init(&ttusb->semi2c);
+
+       mutex_lock(&ttusb->semi2c);
+
+       mutex_init(&ttusb->semusb);
 
        ttusb_setup_interfaces(ttusb);
 
@@ -1504,7 +1505,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        if (ttusb_init_controller(ttusb))
                printk("ttusb_init_controller: error\n");
 
-       up(&ttusb->semi2c);
+       mutex_unlock(&ttusb->semi2c);
 
        dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
        ttusb->adapter.priv = ttusb;
index df83117..44dea32 100644 (file)
@@ -20,7 +20,8 @@
  *
  */
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -115,7 +116,7 @@ struct ttusb_dec {
        unsigned int                    out_pipe;
        unsigned int                    irq_pipe;
        enum ttusb_dec_interface        interface;
-       struct semaphore                usb_sem;
+       struct mutex                    usb_mutex;
 
        void                    *irq_buffer;
        struct urb              *irq_urb;
@@ -124,7 +125,7 @@ struct ttusb_dec {
        dma_addr_t              iso_dma_handle;
        struct urb              *iso_urb[ISO_BUF_COUNT];
        int                     iso_stream_count;
-       struct semaphore        iso_sem;
+       struct mutex            iso_mutex;
 
        u8                              packet[MAX_PVA_LENGTH + 4];
        enum ttusb_dec_packet_type      packet_type;
@@ -273,9 +274,9 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
        if (!b)
                return -ENOMEM;
 
-       if ((result = down_interruptible(&dec->usb_sem))) {
+       if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {
                kfree(b);
-               printk("%s: Failed to down usb semaphore.\n", __FUNCTION__);
+               printk("%s: Failed to lock usb mutex.\n", __FUNCTION__);
                return result;
        }
 
@@ -300,7 +301,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
        if (result) {
                printk("%s: command bulk message failed: error %d\n",
                       __FUNCTION__, result);
-               up(&dec->usb_sem);
+               mutex_unlock(&dec->usb_mutex);
                kfree(b);
                return result;
        }
@@ -311,7 +312,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
        if (result) {
                printk("%s: result bulk message failed: error %d\n",
                       __FUNCTION__, result);
-               up(&dec->usb_sem);
+               mutex_unlock(&dec->usb_mutex);
                kfree(b);
                return result;
        } else {
@@ -327,7 +328,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
                if (cmd_result && b[3] > 0)
                        memcpy(cmd_result, &b[4], b[3]);
 
-               up(&dec->usb_sem);
+               mutex_unlock(&dec->usb_mutex);
 
                kfree(b);
                return 0;
@@ -835,7 +836,7 @@ static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
 
        dprintk("%s\n", __FUNCTION__);
 
-       if (down_interruptible(&dec->iso_sem))
+       if (mutex_lock_interruptible(&dec->iso_mutex))
                return;
 
        dec->iso_stream_count--;
@@ -845,7 +846,7 @@ static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
                        usb_kill_urb(dec->iso_urb[i]);
        }
 
-       up(&dec->iso_sem);
+       mutex_unlock(&dec->iso_mutex);
 }
 
 /* Setting the interface of the DEC tends to take down the USB communications
@@ -890,7 +891,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
 
        dprintk("%s\n", __FUNCTION__);
 
-       if (down_interruptible(&dec->iso_sem))
+       if (mutex_lock_interruptible(&dec->iso_mutex))
                return -EAGAIN;
 
        if (!dec->iso_stream_count) {
@@ -911,7 +912,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
                                        i--;
                                }
 
-                               up(&dec->iso_sem);
+                               mutex_unlock(&dec->iso_mutex);
                                return result;
                        }
                }
@@ -919,7 +920,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
 
        dec->iso_stream_count++;
 
-       up(&dec->iso_sem);
+       mutex_unlock(&dec->iso_mutex);
 
        return 0;
 }
@@ -1229,8 +1230,8 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec)
 {
        dprintk("%s\n", __FUNCTION__);
 
-       sema_init(&dec->usb_sem, 1);
-       sema_init(&dec->iso_sem, 1);
+       mutex_init(&dec->usb_mutex);
+       mutex_init(&dec->iso_mutex);
 
        dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE);
        dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
index a917a90..b602c73 100644 (file)
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include "../../../sound/oss/aci.h"
 #include "miropcm20-rds-core.h"
 
 #define DEBUG 0
 
-static struct semaphore aci_rds_sem;
+static struct mutex aci_rds_mutex;
 
 #define RDS_DATASHIFT          2   /* Bit 2 */
 #define RDS_DATAMASK        (1 << RDS_DATASHIFT)
@@ -181,7 +182,7 @@ int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
 {
        int ret;
 
-       if (down_interruptible(&aci_rds_sem))
+       if (mutex_lock_interruptible(&aci_rds_mutex))
                return -EINTR;
 
        rds_write(cmd);
@@ -192,7 +193,7 @@ int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
        else
                ret = 0;
 
-       up(&aci_rds_sem);
+       mutex_unlock(&aci_rds_mutex);
        
        return ret;
 }
@@ -200,7 +201,7 @@ EXPORT_SYMBOL(aci_rds_cmd);
 
 int __init attach_aci_rds(void)
 {
-       init_MUTEX(&aci_rds_sem);
+       mutex_init(&aci_rds_mutex);
        return 0;
 }
 
index 914deab..557fb5c 100644 (file)
@@ -43,7 +43,7 @@
 
 static int io = CONFIG_RADIO_RTRACK_PORT; 
 static int radio_nr = -1;
-static struct semaphore lock;
+static struct mutex lock;
 
 struct rt_device
 {
@@ -83,23 +83,23 @@ static void rt_incvol(void)
 static void rt_mute(struct rt_device *dev)
 {
        dev->muted = 1;
-       down(&lock);
+       mutex_lock(&lock);
        outb(0xd0, io);                 /* volume steady, off           */
-       up(&lock);
+       mutex_unlock(&lock);
 }
 
 static int rt_setvol(struct rt_device *dev, int vol)
 {
        int i;
 
-       down(&lock);
+       mutex_lock(&lock);
        
        if(vol == dev->curvol) {        /* requested volume = current */
                if (dev->muted) {       /* user is unmuting the card  */
                        dev->muted = 0;
                        outb (0xd8, io);        /* enable card */
                }       
-               up(&lock);
+               mutex_unlock(&lock);
                return 0;
        }
 
@@ -108,7 +108,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
                sleep_delay(2000000);   /* make sure it's totally down  */
                outb(0xd0, io);         /* volume steady, off           */
                dev->curvol = 0;        /* track the volume state!      */
-               up(&lock);
+               mutex_unlock(&lock);
                return 0;
        }
 
@@ -121,7 +121,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
                        rt_decvol();
 
        dev->curvol = vol;
-       up(&lock);
+       mutex_unlock(&lock);
        return 0;
 }
 
@@ -168,7 +168,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
        freq += 171200;                 /* Add 10.7 MHz IF              */
        freq /= 800;                    /* Convert to 50 kHz units      */
        
-       down(&lock);                    /* Stop other ops interfering */
+       mutex_lock(&lock);                      /* Stop other ops interfering */
         
        send_0_byte (io, dev);          /*  0: LSB of frequency         */
 
@@ -196,7 +196,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
        else
                outb (0xd8, io);        /* volume steady + sigstr + on */
                
-       up(&lock);
+       mutex_unlock(&lock);
 
        return 0;
 }
@@ -337,7 +337,7 @@ static int __init rtrack_init(void)
 
        /* Set up the I/O locking */
        
-       init_MUTEX(&lock);
+       mutex_init(&lock);
        
        /* mute card - prevents noisy bootups */
 
index 523be82..83bdae2 100644 (file)
@@ -42,7 +42,7 @@
 static int io = CONFIG_RADIO_AZTECH_PORT; 
 static int radio_nr = -1;
 static int radio_wait_time = 1000;
-static struct semaphore lock;
+static struct mutex lock;
 
 struct az_device
 {
@@ -87,9 +87,9 @@ static void send_1_byte (struct az_device *dev)
 
 static int az_setvol(struct az_device *dev, int vol)
 {
-       down(&lock);
+       mutex_lock(&lock);
        outb (volconvert(vol), io);
-       up(&lock);
+       mutex_unlock(&lock);
        return 0;
 }
 
@@ -122,7 +122,7 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
        frequency += 171200;            /* Add 10.7 MHz IF              */
        frequency /= 800;               /* Convert to 50 kHz units      */
                                        
-       down(&lock);
+       mutex_lock(&lock);
        
        send_0_byte (dev);              /*  0: LSB of frequency       */
 
@@ -152,7 +152,7 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
        udelay (radio_wait_time);
        outb_p(128+64+volconvert(dev->curvol), io);
        
-       up(&lock);
+       mutex_unlock(&lock);
 
        return 0;
 }
@@ -283,7 +283,7 @@ static int __init aztech_init(void)
                return -EBUSY;
        }
 
-       init_MUTEX(&lock);
+       mutex_init(&lock);
        aztech_radio.priv=&aztech_unit;
        
        if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
index 36c9f5b..39c1d91 100644 (file)
 #include <linux/sched.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/videodev.h>
 
+
 #define DRIVER_VERSION "0.05"
 
 #define GPIO_DATA      0x60   /* port offset from ESS_IO_BASE */
@@ -104,7 +105,7 @@ struct radio_device {
                muted,  /* VIDEO_AUDIO_MUTE */
                stereo, /* VIDEO_TUNER_STEREO_ON */     
                tuned;  /* signal strength (0 or 0xffff) */
-       struct  semaphore lock;
+       struct mutex lock;
 };
 
 static u32 radio_bits_get(struct radio_device *dev)
@@ -258,9 +259,9 @@ static int radio_ioctl(struct inode *inode, struct file *file,
        struct radio_device *card = video_get_drvdata(dev);
        int ret;
 
-       down(&card->lock);
+       mutex_lock(&card->lock);
        ret = video_usercopy(inode, file, cmd, arg, radio_function);
-       up(&card->lock);
+       mutex_unlock(&card->lock);
 
        return ret;
 }
@@ -311,7 +312,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
        }
 
        radio_unit->io = pci_resource_start(pdev, 0) + GPIO_DATA;
-       init_MUTEX(&radio_unit->lock);
+       mutex_init(&radio_unit->lock);
 
        maestro_radio_inst = video_device_alloc();
        if (maestro_radio_inst == NULL) {
index c975ddd..f0bf47b 100644 (file)
@@ -37,7 +37,8 @@
 #include <linux/sched.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <linux/pci.h>
 #include <linux/videodev.h>
 
@@ -101,7 +102,7 @@ static struct radio_device
                
        unsigned long freq;
        
-       struct  semaphore lock;
+       struct mutex lock;
 } radio_unit = {0, 0, 0, 0, };
 
 
@@ -267,9 +268,9 @@ static int radio_ioctl(struct inode *inode, struct file *file,
        struct radio_device *card=dev->priv;
        int ret;
        
-       down(&card->lock);
+       mutex_lock(&card->lock);
        ret = video_usercopy(inode, file, cmd, arg, radio_function);
-       up(&card->lock);
+       mutex_unlock(&card->lock);
        return ret;
 }
 
@@ -290,7 +291,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
                goto err_out_free_region;
 
        radio_unit.io = pci_resource_start(pdev, 0);
-       init_MUTEX(&radio_unit.lock);
+       mutex_init(&radio_unit.lock);
        maxiradio_radio.priv = &radio_unit;
 
        if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
index 0229f79..53073b4 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/isapnp.h>
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 struct fmi_device
 {
@@ -37,7 +37,7 @@ struct fmi_device
 static int io = -1; 
 static int radio_nr = -1;
 static struct pnp_dev *dev = NULL;
-static struct semaphore lock;
+static struct mutex lock;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
 /* It is only useful to give freq in intervall of 800 (=0.05Mhz),
@@ -68,16 +68,16 @@ static void outbits(int bits, unsigned int data, int port)
 
 static inline void fmi_mute(int port)
 {
-       down(&lock);
+       mutex_lock(&lock);
        outb(0x00, port);
-       up(&lock);
+       mutex_unlock(&lock);
 }
 
 static inline void fmi_unmute(int port)
 {
-       down(&lock);
+       mutex_lock(&lock);
        outb(0x08, port);
-       up(&lock);
+       mutex_unlock(&lock);
 }
 
 static inline int fmi_setfreq(struct fmi_device *dev)
@@ -85,12 +85,12 @@ static inline int fmi_setfreq(struct fmi_device *dev)
        int myport = dev->port;
        unsigned long freq = dev->curfreq;
 
-       down(&lock);
+       mutex_lock(&lock);
 
        outbits(16, RSF16_ENCODE(freq), myport);
        outbits(8, 0xC0, myport);
        msleep(143);            /* was schedule_timeout(HZ/7) */
-       up(&lock);
+       mutex_unlock(&lock);
        if (dev->curvol) fmi_unmute(myport);
        return 0;
 }
@@ -102,7 +102,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
        int myport = dev->port;
 
        
-       down(&lock);
+       mutex_lock(&lock);
        val = dev->curvol ? 0x08 : 0x00;        /* unmute/mute */
        outb(val, myport);
        outb(val | 0x10, myport);
@@ -110,7 +110,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
        res = (int)inb(myport+1);
        outb(val, myport);
        
-       up(&lock);
+       mutex_unlock(&lock);
        return (res & 2) ? 0 : 0xFFFF;
 }
 
@@ -296,7 +296,7 @@ static int __init fmi_init(void)
        fmi_unit.flags = VIDEO_TUNER_LOW;
        fmi_radio.priv = &fmi_unit;
        
-       init_MUTEX(&lock);
+       mutex_init(&lock);
        
        if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
                release_region(io, 2);
index 099ffb3..bcebd8c 100644 (file)
@@ -19,9 +19,9 @@
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
 #include <linux/videodev.h>    /* kernel radio structs         */
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
-static struct semaphore lock;
+static struct mutex lock;
 
 #undef DEBUG
 //#define DEBUG 1
@@ -238,9 +238,9 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
                        if (fmr2->mute)
                                v->flags |= VIDEO_AUDIO_MUTE;
                        v->mode=VIDEO_MODE_AUTO;
-                       down(&lock);
+                       mutex_lock(&lock);
                        v->signal = fmr2_getsigstr(fmr2);
-                       up(&lock);
+                       mutex_unlock(&lock);
                        return 0;
                }
                case VIDIOCSTUNER:
@@ -274,9 +274,9 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
                        /* set card freq (if not muted) */
                        if (fmr2->curvol && !fmr2->mute)
                        {
-                               down(&lock);
+                               mutex_lock(&lock);
                                fmr2_setfreq(fmr2);
-                               up(&lock);
+                               mutex_unlock(&lock);
                        }
                        return 0;
                }
@@ -318,14 +318,14 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
                        else
                                printk(KERN_DEBUG "mute\n");
 #endif
-                       down(&lock);
+                       mutex_lock(&lock);
                        if (fmr2->curvol && !fmr2->mute)
                        {
                                fmr2_setvolume(fmr2);
                                fmr2_setfreq(fmr2);
                        }
                        else fmr2_mute(fmr2->port);
-                       up(&lock);
+                       mutex_unlock(&lock);
                        return 0;
                }
                case VIDIOCGUNIT:
@@ -380,7 +380,7 @@ static int __init fmr2_init(void)
        fmr2_unit.card_type = 0;
        fmr2_radio.priv = &fmr2_unit;
 
-       init_MUTEX(&lock);
+       mutex_init(&lock);
 
        if (request_region(io, 2, "sf16fmr2"))
        {
@@ -397,10 +397,10 @@ static int __init fmr2_init(void)
        printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
        debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
        /* mute card - prevents noisy bootups */
-       down(&lock);
+       mutex_lock(&lock);
        fmr2_mute(io);
        fmr2_product_info(&fmr2_unit);
-       up(&lock);
+       mutex_unlock(&lock);
        debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
        return 0;
 }
index 8ac9a8e..e509558 100644 (file)
@@ -59,7 +59,7 @@ struct typhoon_device {
        int muted;
        unsigned long curfreq;
        unsigned long mutefreq;
-       struct semaphore lock;
+       struct mutex lock;
 };
 
 static void typhoon_setvol_generic(struct typhoon_device *dev, int vol);
@@ -77,12 +77,12 @@ static int typhoon_get_info(char *buf, char **start, off_t offset, int len);
 
 static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
 {
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        vol >>= 14;                             /* Map 16 bit to 2 bit */
        vol &= 3;
        outb_p(vol / 2, dev->iobase);           /* Set the volume, high bit. */
        outb_p(vol % 2, dev->iobase + 2);       /* Set the volume, low bit. */
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 }
 
 static int typhoon_setfreq_generic(struct typhoon_device *dev,
@@ -102,7 +102,7 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev,
         *
         */
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        x = frequency / 160;
        outval = (x * x + 2500) / 5000;
        outval = (outval * x + 5000) / 10000;
@@ -112,7 +112,7 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev,
        outb_p((outval >> 8) & 0x01, dev->iobase + 4);
        outb_p(outval >> 9, dev->iobase + 6);
        outb_p(outval & 0xff, dev->iobase + 8);
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -337,7 +337,7 @@ static int __init typhoon_init(void)
 #endif /* MODULE */
 
        printk(KERN_INFO BANNER);
-       init_MUTEX(&typhoon_unit.lock);
+       mutex_init(&typhoon_unit.lock);
        io = typhoon_unit.iobase;
        if (!request_region(io, 8, "typhoon")) {
                printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
index d590e80..7bf1a42 100644 (file)
@@ -48,7 +48,7 @@ struct zol_device {
        unsigned long curfreq;
        int muted;
        unsigned int stereo;
-       struct semaphore lock;
+       struct mutex lock;
 };
 
 static int zol_setvol(struct zol_device *dev, int vol)
@@ -57,30 +57,30 @@ static int zol_setvol(struct zol_device *dev, int vol)
        if (dev->muted)
                return 0;
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        if (vol == 0) {
                outb(0, io);
                outb(0, io);
                inb(io + 3);    /* Zoltrix needs to be read to confirm */
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
 
        outb(dev->curvol-1, io);
        msleep(10);
        inb(io + 2);
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
 static void zol_mute(struct zol_device *dev)
 {
        dev->muted = 1;
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        outb(0, io);
        outb(0, io);
        inb(io + 3);            /* Zoltrix needs to be read to confirm */
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 }
 
 static void zol_unmute(struct zol_device *dev)
@@ -104,7 +104,7 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
        bitmask = 0xc480402c10080000ull;
        i = 45;
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        
        outb(0, io);
        outb(0, io);
@@ -149,7 +149,7 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
                udelay(1000);
        }
        
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        
        if(!dev->muted)
        {
@@ -164,7 +164,7 @@ static int zol_getsigstr(struct zol_device *dev)
 {
        int a, b;
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        outb(0x00, io);         /* This stuff I found to do nothing */
        outb(dev->curvol, io);
        msleep(20);
@@ -173,7 +173,7 @@ static int zol_getsigstr(struct zol_device *dev)
        msleep(10);
        b = inb(io);
 
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        
        if (a != b)
                return (0);
@@ -188,7 +188,7 @@ static int zol_is_stereo (struct zol_device *dev)
 {
        int x1, x2;
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        
        outb(0x00, io);
        outb(dev->curvol, io);
@@ -198,7 +198,7 @@ static int zol_is_stereo (struct zol_device *dev)
        msleep(10);
        x2 = inb(io);
 
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        
        if ((x1 == x2) && (x1 == 0xcf))
                return 1;
@@ -350,7 +350,7 @@ static int __init zoltrix_init(void)
        }
        printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
 
-       init_MUTEX(&zoltrix_unit.lock);
+       mutex_init(&zoltrix_unit.lock);
        
        /* mute card - prevents noisy bootups */
 
index d82c8a3..c622a4d 100644 (file)
@@ -26,6 +26,7 @@ config VIDEO_BT848
        select VIDEO_IR
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
+       select VIDEO_MSP3400
        ---help---
          Support for BT848 based frame grabber/overlay boards. This includes
          the Miro, Hauppauge and STB boards. Please read the material in
@@ -142,6 +143,8 @@ config VIDEO_CPIA_USB
          otherwise say N. This will not work with the Creative Webcam III.
          It is also available as a module (cpia_usb).
 
+source "drivers/media/video/cpia2/Kconfig"
+
 config VIDEO_SAA5246A
        tristate "SAA5246A, SAA5281 Teletext processor"
        depends on VIDEO_DEV && I2C
@@ -339,18 +342,53 @@ config VIDEO_M32R_AR_M64278
          Say Y here to use the Renesas M64278E-800 camera module,
          which supports VGA(640x480 pixcels) size of images.
 
-config VIDEO_AUDIO_DECODER
-       tristate "Add support for additional audio chipsets"
+config VIDEO_MSP3400
+       tristate "Micronas MSP34xx audio decoders"
+       depends on VIDEO_DEV && I2C
+       ---help---
+         Support for the Micronas MSP34xx series of audio decoders.
+
+         To compile this driver as a module, choose M here: the
+         module will be called msp3400
+
+config VIDEO_CS53L32A
+       tristate "Cirrus Logic CS53L32A audio ADC"
        depends on VIDEO_DEV && I2C && EXPERIMENTAL
        ---help---
-         Say Y here to compile drivers for WM8775 and CS53L32A audio
-         decoders.
+         Support for the Cirrus Logic CS53L32A low voltage
+         stereo A/D converter.
 
-config VIDEO_DECODER
-       tristate "Add support for additional video chipsets"
+         To compile this driver as a module, choose M here: the
+         module will be called cs53l32a
+
+config VIDEO_WM8775
+       tristate "Wolfson Microelectronics WM8775 audio ADC"
        depends on VIDEO_DEV && I2C && EXPERIMENTAL
        ---help---
-         Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
-         video decoders.
+         Support for the Wolfson Microelectronics WM8775
+         high performance stereo A/D Converter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wm8775
+
+source "drivers/media/video/cx25840/Kconfig"
+
+config VIDEO_SAA711X
+       tristate "Philips SAA7113/4/5 video decoders"
+       depends on VIDEO_DEV && I2C && EXPERIMENTAL
+       ---help---
+         Support for the Philips SAA7113/4/5 video decoders.
+
+         To compile this driver as a module, choose M here: the
+         module will be called saa7115
+
+config VIDEO_SAA7127
+       tristate "Philips SAA7127/9 digital video encoders"
+       depends on VIDEO_DEV && I2C && EXPERIMENTAL
+       ---help---
+         Support for the Philips SAA7127/9 digital video encoders.
+
+         To compile this driver as a module, choose M here: the
+         module will be called saa7127
 
 endmenu
index faf7283..f2bd4c0 100644 (file)
@@ -15,7 +15,7 @@ msp3400-objs  :=      msp3400-driver.o msp3400-kthreads.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o
 
-obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
+obj-$(CONFIG_VIDEO_BT848) += bttv.o tvaudio.o \
        tda7432.o tda9875.o ir-kbd-i2c.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
@@ -44,10 +44,13 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
-obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
-obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o
+obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
-obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
+obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
 obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
 obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
@@ -61,6 +64,8 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
-obj-$(CONFIG_VIDEO_DECODER)     += saa7115.o cx25840/ saa7127.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
index 994b75f..c586f64 100644 (file)
@@ -31,8 +31,8 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
 
-#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 #include <asm/m32r.h>
 #include <asm/io.h>
@@ -117,7 +117,7 @@ struct ar_device {
        int width, height;
        int frame_bytes, line_bytes;
        wait_queue_head_t wait;
-       struct semaphore lock;
+       struct mutex lock;
 };
 
 static int video_nr = -1;      /* video device number (first free) */
@@ -288,7 +288,7 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
        if (ar->mode == AR_MODE_NORMAL)
                arvcr1 |= ARVCR1_NORMAL;
 
-       down(&ar->lock);
+       mutex_lock(&ar->lock);
 
 #if USE_INT
        local_irq_save(flags);
@@ -392,7 +392,7 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
        }
        DEBUG(1, "ret = %d\n", ret);
 out_up:
-       up(&ar->lock);
+       mutex_unlock(&ar->lock);
        return ret;
 }
 
@@ -456,7 +456,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
                    (w->width != AR_WIDTH_QVGA || w->height != AR_HEIGHT_QVGA))
                                return -EINVAL;
 
-               down(&ar->lock);
+               mutex_lock(&ar->lock);
                ar->width = w->width;
                ar->height = w->height;
                if (ar->width == AR_WIDTH_VGA) {
@@ -473,7 +473,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
                        ar->line_bytes = AR_LINE_BYTES_QVGA;
                        ar->mode = AR_MODE_INTERLACE;
                }
-               up(&ar->lock);
+               mutex_unlock(&ar->lock);
                return 0;
        }
        case VIDIOCGFBUF:
@@ -734,7 +734,7 @@ static int ar_initialize(struct video_device *dev)
 void ar_release(struct video_device *vfd)
 {
        struct ar_device *ar = vfd->priv;
-       down(&ar->lock);
+       mutex_lock(&ar->lock);
        video_device_release(vfd);
 }
 
@@ -824,7 +824,7 @@ static int __init ar_init(void)
                ar->line_bytes  = AR_LINE_BYTES_QVGA;
                ar->mode        = AR_MODE_INTERLACE;
        }
-       init_MUTEX(&ar->lock);
+       mutex_init(&ar->lock);
        init_waitqueue_head(&ar->wait);
 
 #if USE_INT
index 9749d6e..abfa6ad 100644 (file)
@@ -137,6 +137,8 @@ MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a li
 MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
 MODULE_PARM_DESC(tuner,"specify installed tuner type");
 MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+               " [some VIA/SIS chipsets are known to have problem with overlay]");
 
 /* ----------------------------------------------------------------------- */
 /* list of card IDs for bt878+ cards                                       */
@@ -275,7 +277,6 @@ static struct CARD {
        { 0x03116000, BTTV_BOARD_SENSORAY311,   "Sensoray 311" },
        { 0x00790e11, BTTV_BOARD_WINDVR,        "Canopus WinDVR PCI" },
        { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX,       "Face to Face Tvmax" },
-       { 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
        { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
        { 0x146caa0c, BTTV_BOARD_PV951,         "ituner spectra8" },
        { 0x200a1295, BTTV_BOARD_PXC200,        "ImageNation PXC200A" },
@@ -297,13 +298,14 @@ static struct CARD {
        * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB,  "Hauppauge ImpactVCB" }, */
 
        /* DVB cards (using pci function .1 for mpeg data xfer) */
-       { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
-       { 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
        { 0x001c11bd, BTTV_BOARD_PINNACLESAT,   "Pinnacle PCTV Sat" },
+       { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+       { 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
        { 0x002611bd, BTTV_BOARD_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
        { 0x00011822, BTTV_BOARD_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
        { 0xfc00270f, BTTV_BOARD_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
        { 0x07711461, BTTV_BOARD_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
+       { 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
        { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
        { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
 
@@ -4944,12 +4946,14 @@ void __devinit bttv_check_chipset(void)
        if (vsfx)
                printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
        if (pcipci_fail) {
-               printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
+               printk(KERN_INFO "bttv: bttv and your chipset may not work "
+                                                       "together.\n");
                if (!no_overlay) {
-                       printk(KERN_WARNING "bttv: overlay will be disabled.\n");
+                       printk(KERN_INFO "bttv: overlay will be disabled.\n");
                        no_overlay = 1;
                } else {
-                       printk(KERN_WARNING "bttv: overlay forced. Use this option at your own risk.\n");
+                       printk(KERN_INFO "bttv: overlay forced. Use this "
+                                               "option at your own risk.\n");
                }
        }
        if (UNSET != latency)
index 578b200..c0415d6 100644 (file)
@@ -1965,7 +1965,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
                BUG();
        }
 
-       down(&fh->cap.lock);
+       mutex_lock(&fh->cap.lock);
                kfree(fh->ov.clips);
        fh->ov.clips    = clips;
        fh->ov.nclips   = n;
@@ -1986,7 +1986,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
                bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
                retval = bttv_switch_overlay(btv,fh,new);
        }
-       up(&fh->cap.lock);
+       mutex_unlock(&fh->cap.lock);
        return retval;
 }
 
@@ -2166,7 +2166,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
                fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 
                /* update our state informations */
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                fh->fmt              = fmt;
                fh->cap.field        = f->fmt.pix.field;
                fh->cap.last         = V4L2_FIELD_NONE;
@@ -2175,7 +2175,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
                btv->init.fmt        = fmt;
                btv->init.width      = f->fmt.pix.width;
                btv->init.height     = f->fmt.pix.height;
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
 
                return 0;
        }
@@ -2282,7 +2282,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                fmt = format_by_palette(pic->palette);
                if (NULL == fmt)
                        return -EINVAL;
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                if (fmt->depth != pic->depth) {
                        retval = -EINVAL;
                        goto fh_unlock_and_return;
@@ -2313,7 +2313,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                bt848_contrast(btv,pic->contrast);
                bt848_hue(btv,pic->hue);
                bt848_sat(btv,pic->colour);
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                return 0;
        }
 
@@ -2379,7 +2379,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                        return -EPERM;
                end = (unsigned long)fbuf->base +
                        fbuf->height * fbuf->bytesperline;
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                retval = -EINVAL;
 
                switch (fbuf->depth) {
@@ -2417,7 +2417,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                        btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
                else
                        btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                return 0;
        }
 
@@ -2440,7 +2440,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
                        return -EBUSY;
 
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                if (*on) {
                        fh->ov.tvnorm = btv->tvnorm;
                        new = videobuf_alloc(sizeof(*new));
@@ -2451,7 +2451,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
 
                /* switch over */
                retval = bttv_switch_overlay(btv,fh,new);
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                return retval;
        }
 
@@ -2460,7 +2460,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                struct video_mbuf *mbuf = arg;
                unsigned int i;
 
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
                                             V4L2_MEMORY_MMAP);
                if (retval < 0)
@@ -2470,7 +2470,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                mbuf->size   = gbuffers * gbufsize;
                for (i = 0; i < gbuffers; i++)
                        mbuf->offsets[i] = i * gbufsize;
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                return 0;
        }
        case VIDIOCMCAPTURE:
@@ -2482,7 +2482,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                if (vm->frame >= VIDEO_MAX_FRAME)
                        return -EINVAL;
 
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                retval = -EINVAL;
                buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
                if (NULL == buf)
@@ -2504,7 +2504,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                spin_lock_irqsave(&btv->s_lock,flags);
                buffer_queue(&fh->cap,&buf->vb);
                spin_unlock_irqrestore(&btv->s_lock,flags);
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                return 0;
        }
        case VIDIOCSYNC:
@@ -2515,7 +2515,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                if (*frame >= VIDEO_MAX_FRAME)
                        return -EINVAL;
 
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                retval = -EINVAL;
                buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
                if (NULL == buf)
@@ -2535,7 +2535,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                        retval = -EINVAL;
                        break;
                }
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                return retval;
        }
 
@@ -2719,7 +2719,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
                        return -EINVAL;
 
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                retval = -EINVAL;
                if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
                        if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
@@ -2759,7 +2759,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                                retval = bttv_switch_overlay(btv,fh,new);
                        }
                }
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                return retval;
        }
 
@@ -2890,7 +2890,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
        return 0;
 
  fh_unlock_and_return:
-       up(&fh->cap.lock);
+       mutex_unlock(&fh->cap.lock);
        return retval;
 }
 
@@ -2957,16 +2957,16 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
                buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
        } else {
                /* read() capture */
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                if (NULL == fh->cap.read_buf) {
                        /* need to capture a new frame */
                        if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
-                               up(&fh->cap.lock);
+                               mutex_unlock(&fh->cap.lock);
                                return POLLERR;
                        }
                        fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
                        if (NULL == fh->cap.read_buf) {
-                               up(&fh->cap.lock);
+                               mutex_unlock(&fh->cap.lock);
                                return POLLERR;
                        }
                        fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
@@ -2974,13 +2974,13 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
                        if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
                                kfree (fh->cap.read_buf);
                                fh->cap.read_buf = NULL;
-                               up(&fh->cap.lock);
+                               mutex_unlock(&fh->cap.lock);
                                return POLLERR;
                        }
                        fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
                        fh->cap.read_off = 0;
                }
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                buf = (struct bttv_buffer*)fh->cap.read_buf;
        }
 
index 221b36e..69efa0e 100644 (file)
 #include "bttv.h"
 #include "bttvp.h"
 
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = {
-       [ 34 ] = KEY_KP0,
-       [ 40 ] = KEY_KP1,
-       [ 24 ] = KEY_KP2,
-       [ 56 ] = KEY_KP3,
-       [ 36 ] = KEY_KP4,
-       [ 20 ] = KEY_KP5,
-       [ 52 ] = KEY_KP6,
-       [ 44 ] = KEY_KP7,
-       [ 28 ] = KEY_KP8,
-       [ 60 ] = KEY_KP9,
-
-       [ 48 ] = KEY_EJECTCD,     // Unmarked on my controller
-       [  0 ] = KEY_POWER,
-       [ 18 ] = BTN_LEFT,        // DISPLAY/L
-       [ 50 ] = BTN_RIGHT,       // LOOP/R
-       [ 10 ] = KEY_MUTE,
-       [ 38 ] = KEY_RECORD,
-       [ 22 ] = KEY_PAUSE,
-       [ 54 ] = KEY_STOP,
-       [ 30 ] = KEY_VOLUMEDOWN,
-       [ 62 ] = KEY_VOLUMEUP,
-
-       [ 32 ] = KEY_TUNER,       // TV/FM
-       [ 16 ] = KEY_CD,
-       [  8 ] = KEY_VIDEO,
-       [  4 ] = KEY_AUDIO,
-       [ 12 ] = KEY_ZOOM,        // full screen
-       [  2 ] = KEY_INFO,        // preview
-       [ 42 ] = KEY_SEARCH,      // autoscan
-       [ 26 ] = KEY_STOP,        // freeze
-       [ 58 ] = KEY_RECORD,      // capture
-       [  6 ] = KEY_PLAY,        // unmarked
-       [ 46 ] = KEY_RED,         // unmarked
-       [ 14 ] = KEY_GREEN,       // unmarked
-
-       [ 33 ] = KEY_YELLOW,      // unmarked
-       [ 17 ] = KEY_CHANNELDOWN,
-       [ 49 ] = KEY_CHANNELUP,
-       [  1 ] = KEY_BLUE,        // unmarked
-};
-
-/* Matt Jesson <dvb@jesson.eclipse.co.uk */
-static IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
-       [ 0x28 ] = KEY_KP0,         //'0' / 'enter'
-       [ 0x22 ] = KEY_KP1,         //'1'
-       [ 0x12 ] = KEY_KP2,         //'2' / 'up arrow'
-       [ 0x32 ] = KEY_KP3,         //'3'
-       [ 0x24 ] = KEY_KP4,         //'4' / 'left arrow'
-       [ 0x14 ] = KEY_KP5,         //'5'
-       [ 0x34 ] = KEY_KP6,         //'6' / 'right arrow'
-       [ 0x26 ] = KEY_KP7,         //'7'
-       [ 0x16 ] = KEY_KP8,         //'8' / 'down arrow'
-       [ 0x36 ] = KEY_KP9,         //'9'
-
-       [ 0x20 ] = KEY_LIST,        // 'source'
-       [ 0x10 ] = KEY_TEXT,        // 'teletext'
-       [ 0x00 ] = KEY_POWER,       // 'power'
-       [ 0x04 ] = KEY_AUDIO,       // 'audio'
-       [ 0x06 ] = KEY_ZOOM,        // 'full screen'
-       [ 0x18 ] = KEY_VIDEO,       // 'display'
-       [ 0x38 ] = KEY_SEARCH,      // 'loop'
-       [ 0x08 ] = KEY_INFO,        // 'preview'
-       [ 0x2a ] = KEY_REWIND,      // 'backward <<'
-       [ 0x1a ] = KEY_FASTFORWARD, // 'forward >>'
-       [ 0x3a ] = KEY_RECORD,      // 'capture'
-       [ 0x0a ] = KEY_MUTE,        // 'mute'
-       [ 0x2c ] = KEY_RECORD,      // 'record'
-       [ 0x1c ] = KEY_PAUSE,       // 'pause'
-       [ 0x3c ] = KEY_STOP,        // 'stop'
-       [ 0x0c ] = KEY_PLAY,        // 'play'
-       [ 0x2e ] = KEY_RED,         // 'red'
-       [ 0x01 ] = KEY_BLUE,        // 'blue' / 'cancel'
-       [ 0x0e ] = KEY_YELLOW,      // 'yellow' / 'ok'
-       [ 0x21 ] = KEY_GREEN,       // 'green'
-       [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -'
-       [ 0x31 ] = KEY_CHANNELUP,   // 'channel +'
-       [ 0x1e ] = KEY_VOLUMEDOWN,  // 'volume -'
-       [ 0x3e ] = KEY_VOLUMEUP,    // 'volume +'
-};
-
-/* Attila Kondoros <attila.kondoros@chello.hu> */
-static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
-
-       [  1 ] = KEY_KP1,
-       [  2 ] = KEY_KP2,
-       [  3 ] = KEY_KP3,
-       [  4 ] = KEY_KP4,
-       [  5 ] = KEY_KP5,
-       [  6 ] = KEY_KP6,
-       [  7 ] = KEY_KP7,
-       [  8 ] = KEY_KP8,
-       [  9 ] = KEY_KP9,
-       [  0 ] = KEY_KP0,
-       [ 23 ] = KEY_LAST,        // +100
-       [ 10 ] = KEY_LIST,        // recall
-
-
-       [ 28 ] = KEY_TUNER,       // TV/FM
-       [ 21 ] = KEY_SEARCH,      // scan
-       [ 18 ] = KEY_POWER,       // power
-       [ 31 ] = KEY_VOLUMEDOWN,  // vol up
-       [ 27 ] = KEY_VOLUMEUP,    // vol down
-       [ 30 ] = KEY_CHANNELDOWN, // chn up
-       [ 26 ] = KEY_CHANNELUP,   // chn down
-
-       [ 17 ] = KEY_VIDEO,       // video
-       [ 15 ] = KEY_ZOOM,        // full screen
-       [ 19 ] = KEY_MUTE,        // mute/unmute
-       [ 16 ] = KEY_TEXT,        // min
-
-       [ 13 ] = KEY_STOP,        // freeze
-       [ 14 ] = KEY_RECORD,      // record
-       [ 29 ] = KEY_PLAYPAUSE,   // stop
-       [ 25 ] = KEY_PLAY,        // play
-
-       [ 22 ] = KEY_GOTO,        // osd
-       [ 20 ] = KEY_REFRESH,     // default
-       [ 12 ] = KEY_KPPLUS,      // fine tune >>>>
-       [ 24 ] = KEY_KPMINUS      // fine tune <<<<
-};
-
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
-
-       [ 30 ] = KEY_POWER,       // power
-       [ 7  ] = KEY_MEDIA,       // source
-       [ 28 ] = KEY_SEARCH,      // scan
-
-/* FIXME: duplicate keycodes?
- *
- * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
- * The GPIO values are
- * 6397fb for both "Scan <" and "CH -",
- * 639ffb for "Scan >" and "CH+",
- * 6384fb for "Tune <" and "<<<",
- * 638cfb for "Tune >" and ">>>", regardless of the mask.
- *
- *     [ 23 ] = KEY_BACK,        // fm scan <<
- *     [ 31 ] = KEY_FORWARD,     // fm scan >>
- *
- *     [ 4  ] = KEY_LEFT,        // fm tuning <
- *     [ 12 ] = KEY_RIGHT,       // fm tuning >
- *
- * For now, these four keys are disabled. Pressing them will generate
- * the CH+/CH-/<<</>>> events
- */
-
-       [ 3  ] = KEY_TUNER,       // TV/FM
-
-       [ 0  ] = KEY_RECORD,
-       [ 8  ] = KEY_STOP,
-       [ 17 ] = KEY_PLAY,
-
-       [ 26 ] = KEY_PLAYPAUSE,   // freeze
-       [ 25 ] = KEY_ZOOM,        // zoom
-       [ 15 ] = KEY_TEXT,        // min
-
-       [ 1  ] = KEY_KP1,
-       [ 11 ] = KEY_KP2,
-       [ 27 ] = KEY_KP3,
-       [ 5  ] = KEY_KP4,
-       [ 9  ] = KEY_KP5,
-       [ 21 ] = KEY_KP6,
-       [ 6  ] = KEY_KP7,
-       [ 10 ] = KEY_KP8,
-       [ 18 ] = KEY_KP9,
-       [ 2  ] = KEY_KP0,
-       [ 16 ] = KEY_LAST,        // +100
-       [ 19 ] = KEY_LIST,        // recall
-
-       [ 31 ] = KEY_CHANNELUP,   // chn down
-       [ 23 ] = KEY_CHANNELDOWN, // chn up
-       [ 22 ] = KEY_VOLUMEUP,    // vol down
-       [ 20 ] = KEY_VOLUMEDOWN,  // vol up
-
-       [ 4  ] = KEY_KPMINUS,     // <<<
-       [ 14 ] = KEY_SETUP,       // function
-       [ 12 ] = KEY_KPPLUS,      // >>>
-
-       [ 13 ] = KEY_GOTO,        // mts
-       [ 29 ] = KEY_REFRESH,     // reset
-       [ 24 ] = KEY_MUTE         // mute/unmute
-};
-
-static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
-       [0x00] = KEY_KP0,
-       [0x01] = KEY_KP1,
-       [0x02] = KEY_KP2,
-       [0x03] = KEY_KP3,
-       [0x04] = KEY_KP4,
-       [0x05] = KEY_KP5,
-       [0x06] = KEY_KP6,
-       [0x07] = KEY_KP7,
-       [0x08] = KEY_KP8,
-       [0x09] = KEY_KP9,
-       [0x0a] = KEY_TV,
-       [0x0b] = KEY_AUX,
-       [0x0c] = KEY_DVD,
-       [0x0d] = KEY_POWER,
-       [0x0e] = KEY_MHP,       /* labelled 'Picture' */
-       [0x0f] = KEY_AUDIO,
-       [0x10] = KEY_INFO,
-       [0x11] = KEY_F13,       /* 16:9 */
-       [0x12] = KEY_F14,       /* 14:9 */
-       [0x13] = KEY_EPG,
-       [0x14] = KEY_EXIT,
-       [0x15] = KEY_MENU,
-       [0x16] = KEY_UP,
-       [0x17] = KEY_DOWN,
-       [0x18] = KEY_LEFT,
-       [0x19] = KEY_RIGHT,
-       [0x1a] = KEY_ENTER,
-       [0x1b] = KEY_CHANNELUP,
-       [0x1c] = KEY_CHANNELDOWN,
-       [0x1d] = KEY_VOLUMEUP,
-       [0x1e] = KEY_VOLUMEDOWN,
-       [0x1f] = KEY_RED,
-       [0x20] = KEY_GREEN,
-       [0x21] = KEY_YELLOW,
-       [0x22] = KEY_BLUE,
-       [0x23] = KEY_SUBTITLE,
-       [0x24] = KEY_F15,       /* AD */
-       [0x25] = KEY_TEXT,
-       [0x26] = KEY_MUTE,
-       [0x27] = KEY_REWIND,
-       [0x28] = KEY_STOP,
-       [0x29] = KEY_PLAY,
-       [0x2a] = KEY_FASTFORWARD,
-       [0x2b] = KEY_F16,       /* chapter */
-       [0x2c] = KEY_PAUSE,
-       [0x2d] = KEY_PLAY,
-       [0x2e] = KEY_RECORD,
-       [0x2f] = KEY_F17,       /* picture in picture */
-       [0x30] = KEY_KPPLUS,    /* zoom in */
-       [0x31] = KEY_KPMINUS,   /* zoom out */
-       [0x32] = KEY_F18,       /* capture */
-       [0x33] = KEY_F19,       /* web */
-       [0x34] = KEY_EMAIL,
-       [0x35] = KEY_PHONE,
-       [0x36] = KEY_PC
-};
 
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
@@ -573,7 +328,8 @@ int bttv_input_init(struct bttv *btv)
                ir->polling      = 50; // ms
                break;
        case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
-               ir_codes         = ir_codes_conceptronic;
+       case BTTV_BOARD_CONTVFMI:
+               ir_codes         = ir_codes_pixelview;
                ir->mask_keycode = 0x001F00;
                ir->mask_keyup   = 0x006000;
                ir->polling      = 50; // ms
index b40e973..344f84e 100644 (file)
@@ -51,8 +51,10 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
        int rc;
 
        /* estimate risc mem: worst case is one write per page border +
-          one write per scan line + sync + jump (all 2 dwords) */
-       instructions  = (bpl * lines) / PAGE_SIZE + lines;
+          one write per scan line + sync + jump (all 2 dwords).  padding
+          can cause next bpl to start close to a page border.  First DMA
+          region may be smaller than PAGE_SIZE */
+       instructions  = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
        instructions += 2;
        if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
                return rc;
@@ -104,7 +106,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
        return 0;
 }
 
@@ -222,7 +224,7 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
        return 0;
 }
 
@@ -274,6 +276,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
                if (line > maxy)
                        btcx_calc_skips(line, ov->w.width, &maxy,
                                        skips, &nskips, ov->clips, ov->nclips);
+               else
+                       nskips = 0;
 
                /* write out risc code */
                for (start = 0, skip = 0; start < ov->w.width; start = end) {
@@ -307,7 +311,7 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
        kfree(skips);
        return 0;
 }
@@ -507,8 +511,7 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
 void
 bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
 {
-       if (in_interrupt())
-               BUG();
+       BUG_ON(in_interrupt());
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma);
        videobuf_dma_free(&buf->vb.dma);
index 6bad93e..d97b7d8 100644 (file)
@@ -73,7 +73,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "bw-qcam.h"
@@ -168,7 +168,7 @@ static struct qcam_device *qcam_init(struct parport *port)
        
        memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
        
-       init_MUTEX(&q->lock);
+       mutex_init(&q->lock);
 
        q->port_mode = (QC_ANY | QC_NOTSET);
        q->width = 320;
@@ -772,9 +772,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                        qcam->whitebal = p->whiteness>>8;
                        qcam->bpp = p->depth;
 
-                       down(&qcam->lock);                      
+                       mutex_lock(&qcam->lock);
                        qc_setscanmode(qcam);
-                       up(&qcam->lock);
+                       mutex_unlock(&qcam->lock);
                        qcam->status |= QC_PARAM_CHANGE;
 
                        return 0;
@@ -805,9 +805,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                                qcam->height = 240;
                                qcam->transfer_scale = 1;
                        }
-                       down(&qcam->lock);
+                       mutex_lock(&qcam->lock);
                        qc_setscanmode(qcam);
-                       up(&qcam->lock);
+                       mutex_unlock(&qcam->lock);
                        
                        /* We must update the camera before we grab. We could
                           just have changed the grab size */
@@ -854,7 +854,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
        int len;
        parport_claim_or_block(qcam->pdev);
        
-       down(&qcam->lock);
+       mutex_lock(&qcam->lock);
        
        qc_reset(qcam);
 
@@ -864,7 +864,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
 
        len=qc_capture(qcam, buf,count);
        
-       up(&qcam->lock);
+       mutex_unlock(&qcam->lock);
        
        parport_release(qcam->pdev);
        return len;
index 723e8ad..6701daf 100644 (file)
@@ -55,7 +55,7 @@ struct qcam_device {
        struct video_device vdev;
        struct pardevice *pdev;
        struct parport *pport;
-       struct semaphore lock;
+       struct mutex lock;
        int width, height;
        int bpp;
        int mode;
index 9976db4..8211fd8 100644 (file)
@@ -34,7 +34,8 @@
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 struct qcam_device {
@@ -47,7 +48,7 @@ struct qcam_device {
        int contrast, brightness, whitebal;
        int top, left;
        unsigned int bidirectional;
-       struct semaphore lock;
+       struct mutex lock;
 };
 
 /* cameras maximum */
@@ -581,11 +582,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                        qcam->contrast = p->contrast>>8;
                        qcam->whitebal = p->whiteness>>8;
 
-                       down(&qcam->lock);                      
+                       mutex_lock(&qcam->lock);
                        parport_claim_or_block(qcam->pdev);
                        qc_setup(qcam); 
                        parport_release(qcam->pdev);
-                       up(&qcam->lock);
+                       mutex_unlock(&qcam->lock);
                        return 0;
                }
                case VIDIOCSWIN:
@@ -628,11 +629,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
 #endif
                        /* Ok we figured out what to use from our 
                           wide choice */
-                       down(&qcam->lock);
+                       mutex_lock(&qcam->lock);
                        parport_claim_or_block(qcam->pdev);
                        qc_setup(qcam);
                        parport_release(qcam->pdev);
-                       up(&qcam->lock);
+                       mutex_unlock(&qcam->lock);
                        return 0;
                }
                case VIDIOCGWIN:
@@ -672,12 +673,12 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
        struct qcam_device *qcam=(struct qcam_device *)v;
        int len;
 
-       down(&qcam->lock);
+       mutex_lock(&qcam->lock);
        parport_claim_or_block(qcam->pdev);
        /* Probably should have a semaphore against multiple users */
        len = qc_capture(qcam, buf,count); 
        parport_release(qcam->pdev);
-       up(&qcam->lock);
+       mutex_unlock(&qcam->lock);
        return len;
 }
 
@@ -727,7 +728,7 @@ static struct qcam_device *qcam_init(struct parport *port)
        
        memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
 
-       init_MUTEX(&q->lock);
+       mutex_init(&q->lock);
        q->width = q->ccd_width = 320;
        q->height = q->ccd_height = 240;
        q->mode = QC_MILLIONS | QC_DECIMATION_1;
index 85d964b..d93a561 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/pagemap.h>
 #include <linux/delay.h>
 #include <asm/io.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -622,7 +622,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
        
        buffer = page;
        
-       if (down_interruptible(&cam->param_lock))
+       if (mutex_lock_interruptible(&cam->param_lock))
                return -ERESTARTSYS;
        
        /*
@@ -1350,7 +1350,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
        } else
                DBG("error: %d\n", retval);
        
-       up(&cam->param_lock);
+       mutex_unlock(&cam->param_lock);
        
 out:
        free_page((unsigned long)page);
@@ -1664,7 +1664,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
        case CPIA_COMMAND_GetColourParams:
        case CPIA_COMMAND_GetColourBalance:
        case CPIA_COMMAND_GetExposure:
-               down(&cam->param_lock);
+               mutex_lock(&cam->param_lock);
                datasize=8;
                break;
        case CPIA_COMMAND_ReadMCPorts: 
@@ -1691,7 +1691,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
                if (command == CPIA_COMMAND_GetColourParams ||
                    command == CPIA_COMMAND_GetColourBalance ||
                    command == CPIA_COMMAND_GetExposure)
-                       up(&cam->param_lock);
+                       mutex_unlock(&cam->param_lock);
        } else {
                switch(command) {
                case CPIA_COMMAND_GetCPIAVersion:
@@ -1726,13 +1726,13 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
                        cam->params.colourParams.brightness = data[0];
                        cam->params.colourParams.contrast = data[1];
                        cam->params.colourParams.saturation = data[2];
-                       up(&cam->param_lock);
+                       mutex_unlock(&cam->param_lock);
                        break;
                case CPIA_COMMAND_GetColourBalance:
                        cam->params.colourBalance.redGain = data[0];
                        cam->params.colourBalance.greenGain = data[1];
                        cam->params.colourBalance.blueGain = data[2];
-                       up(&cam->param_lock);
+                       mutex_unlock(&cam->param_lock);
                        break;
                case CPIA_COMMAND_GetExposure:
                        cam->params.exposure.gain = data[0];
@@ -1743,7 +1743,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
                        cam->params.exposure.green1Comp = data[5];
                        cam->params.exposure.green2Comp = data[6];
                        cam->params.exposure.blueComp = data[7];
-                       up(&cam->param_lock);
+                       mutex_unlock(&cam->param_lock);
                        break;
 
                case CPIA_COMMAND_ReadMCPorts: 
@@ -2059,7 +2059,7 @@ static int parse_picture(struct cam_data *cam, int size)
        int rows, cols, linesize, subsample_422;
 
        /* make sure params don't change while we are decoding */
-       down(&cam->param_lock);
+       mutex_lock(&cam->param_lock);
 
        obuf = cam->decompressed_frame.data;
        end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
@@ -2069,26 +2069,26 @@ static int parse_picture(struct cam_data *cam, int size)
 
        if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
                LOG("header not found\n");
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return -1;
        }
 
        if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
                LOG("wrong video size\n");
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return -1;
        }
        
        if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
                LOG("illegal subtype %d\n",ibuf[17]);
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return -1;
        }
        subsample_422 = ibuf[17] == SUBSAMPLE_422;
        
        if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
                LOG("illegal yuvorder %d\n",ibuf[18]);
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return -1;
        }
        in_uyvy = ibuf[18] == YUVORDER_UYVY;
@@ -2098,7 +2098,7 @@ static int parse_picture(struct cam_data *cam, int size)
            (ibuf[26] != cam->params.roi.rowStart) ||
            (ibuf[27] != cam->params.roi.rowEnd)) {
                LOG("ROI mismatch\n");
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return -1;
        }
        cols = 8*(ibuf[25] - ibuf[24]);
@@ -2107,14 +2107,14 @@ static int parse_picture(struct cam_data *cam, int size)
        
        if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
                LOG("illegal compression %d\n",ibuf[28]);
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return -1;
        }
        compressed = (ibuf[28] == COMPRESSED);
        
        if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
                LOG("illegal decimation %d\n",ibuf[29]);
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return -1;
        }
        decimation = (ibuf[29] == DECIMATION_ENAB);     
@@ -2130,7 +2130,7 @@ static int parse_picture(struct cam_data *cam, int size)
        cam->params.status.vpStatus = ibuf[38];
        cam->params.status.errorCode = ibuf[39];
        cam->fps = ibuf[41];
-       up(&cam->param_lock);
+       mutex_unlock(&cam->param_lock);
        
        linesize = skipcount(cols, out_fmt);
        ibuf += FRAME_HEADER_SIZE;
@@ -2271,9 +2271,9 @@ static int find_over_exposure(int brightness)
 /* update various camera modes and settings */
 static void dispatch_commands(struct cam_data *cam)
 {
-       down(&cam->param_lock);
+       mutex_lock(&cam->param_lock);
        if (cam->cmd_queue==COMMAND_NONE) {
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return;
        }
        DEB_BYTE(cam->cmd_queue);
@@ -2415,7 +2415,7 @@ static void dispatch_commands(struct cam_data *cam)
          }
 
        cam->cmd_queue = COMMAND_NONE;
-       up(&cam->param_lock);
+       mutex_unlock(&cam->param_lock);
        return;
 }
 
@@ -2562,7 +2562,7 @@ static void monitor_exposure(struct cam_data *cam)
        gain = data[2];
        coarseL = data[3];
 
-       down(&cam->param_lock);
+       mutex_lock(&cam->param_lock);
        light_exp = cam->params.colourParams.brightness +
                    TC - 50 + EXP_ACC_LIGHT;
        if(light_exp > 255)
@@ -2762,7 +2762,7 @@ static void monitor_exposure(struct cam_data *cam)
                        LOG("Automatically increasing sensor_fps\n");
                }
        }
-       up(&cam->param_lock);
+       mutex_unlock(&cam->param_lock);
 }
 
 /*-----------------------------------------------------------------*/
@@ -2778,10 +2778,10 @@ static void restart_flicker(struct cam_data *cam)
        int cam_exposure, old_exp;
        if(!FIRMWARE_VERSION(1,2))
                return;
-       down(&cam->param_lock);
+       mutex_lock(&cam->param_lock);
        if(cam->params.flickerControl.flickerMode == 0 ||
           cam->raw_image[39] == 0) {
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                return;
        }
        cam_exposure = cam->raw_image[39]*2;
@@ -2810,7 +2810,7 @@ static void restart_flicker(struct cam_data *cam)
                        cam->exposure_status = EXPOSURE_NORMAL;
 
        }
-       up(&cam->param_lock);
+       mutex_unlock(&cam->param_lock);
 }
 #undef FIRMWARE_VERSION
 
@@ -3186,7 +3186,7 @@ static int cpia_open(struct inode *inode, struct file *file)
        if (!try_module_get(cam->ops->owner))
                return -ENODEV;
 
-       down(&cam->busy_lock);
+       mutex_lock(&cam->busy_lock);
        err = -ENOMEM;
        if (!cam->raw_image) {
                cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
@@ -3227,7 +3227,7 @@ static int cpia_open(struct inode *inode, struct file *file)
        
        ++cam->open_count;
        file->private_data = dev;
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        return 0;
 
  oops:
@@ -3239,7 +3239,7 @@ static int cpia_open(struct inode *inode, struct file *file)
                rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
                cam->raw_image = NULL;
        }
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        put_cam(cam->ops);
        return err;
 }
@@ -3303,24 +3303,24 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
        int err;
 
        /* make this _really_ smp and multithread-safe */
-       if (down_interruptible(&cam->busy_lock))
+       if (mutex_lock_interruptible(&cam->busy_lock))
                return -EINTR;
 
        if (!buf) {
                DBG("buf NULL\n");
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -EINVAL;
        }
 
        if (!count) {
                DBG("count 0\n");
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return 0;
        }
 
        if (!cam->ops) {
                DBG("ops NULL\n");
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -ENODEV;
        }
 
@@ -3329,7 +3329,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
        cam->mmap_kludge=0;
        if((err = fetch_frame(cam)) != 0) {
                DBG("ERROR from fetch_frame: %d\n", err);
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return err;
        }
        cam->decompressed_frame.state = FRAME_UNUSED;
@@ -3338,17 +3338,17 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
        if (cam->decompressed_frame.count > count) {
                DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
                    (unsigned long) count);
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -EFAULT;
        }
        if (copy_to_user(buf, cam->decompressed_frame.data,
                        cam->decompressed_frame.count)) {
                DBG("copy_to_user failed\n");
-               up(&cam->busy_lock);
+               mutex_unlock(&cam->busy_lock);
                return -EFAULT;
        }
 
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        return cam->decompressed_frame.count;
 }
 
@@ -3363,7 +3363,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                return -ENODEV;
        
        /* make this _really_ smp-safe */
-       if (down_interruptible(&cam->busy_lock))
+       if (mutex_lock_interruptible(&cam->busy_lock))
                return -EINTR;
 
        //DBG("cpia_ioctl: %u\n", ioctlnr);
@@ -3439,7 +3439,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                        break;
                }
 
-               down(&cam->param_lock);
+               mutex_lock(&cam->param_lock);
                /* brightness, colour, contrast need no check 0-65535 */
                cam->vp = *vp;
                /* update cam->params.colourParams */
@@ -3466,7 +3466,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 
                /* queue command to update camera */
                cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
                DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
                    vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
                    vp->contrast);
@@ -3501,13 +3501,13 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                /* we set the video window to something smaller or equal to what
                * is requested by the user???
                */
-               down(&cam->param_lock);
+               mutex_lock(&cam->param_lock);
                if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
                        int video_size = match_videosize(vw->width, vw->height);
 
                        if (video_size < 0) {
                                retval = -EINVAL;
-                               up(&cam->param_lock);
+                               mutex_unlock(&cam->param_lock);
                                break;
                        }
                        cam->video_size = video_size;
@@ -3520,7 +3520,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                        cam->cmd_queue |= COMMAND_SETFORMAT;
                }
 
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
 
                /* setformat ignored by camera during streaming,
                 * so stop/dispatch/start */
@@ -3682,7 +3682,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 
                DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
                
-               down(&cam->param_lock);
+               mutex_lock(&cam->param_lock);
                
                cam->vc.x      = vc->x;
                cam->vc.y      = vc->y;
@@ -3692,7 +3692,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                set_vw_size(cam);
                cam->cmd_queue |= COMMAND_SETFORMAT;
 
-               up(&cam->param_lock);
+               mutex_unlock(&cam->param_lock);
 
                /* setformat ignored by camera during streaming,
                 * so stop/dispatch/start */
@@ -3736,7 +3736,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
        return retval;
 } 
 
@@ -3769,12 +3769,12 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
                return -ENODEV;
        
        /* make this _really_ smp-safe */
-       if (down_interruptible(&cam->busy_lock))
+       if (mutex_lock_interruptible(&cam->busy_lock))
                return -EINTR;
 
        if (!cam->frame_buf) {  /* we do lazy allocation */
                if ((retval = allocate_frame_buf(cam))) {
-                       up(&cam->busy_lock);
+                       mutex_unlock(&cam->busy_lock);
                        return retval;
                }
        }
@@ -3783,7 +3783,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
        while (size > 0) {
                page = vmalloc_to_pfn((void *)pos);
                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       up(&cam->busy_lock);
+                       mutex_unlock(&cam->busy_lock);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -3795,7 +3795,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
        }
 
        DBG("cpia_mmap: %ld\n", size);
-       up(&cam->busy_lock);
+       mutex_unlock(&cam->busy_lock);
 
        return 0;
 }
@@ -3936,8 +3936,8 @@ static void init_camera_struct(struct cam_data *cam,
        memset(cam, 0, sizeof(struct cam_data));
 
        cam->ops = ops;
-       init_MUTEX(&cam->param_lock);
-       init_MUTEX(&cam->busy_lock);
+       mutex_init(&cam->param_lock);
+       mutex_init(&cam->busy_lock);
 
        reset_camera_struct(cam);
 
index f629b69..de66782 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/videodev.h>
 #include <linux/list.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 struct cpia_camera_ops
 {
@@ -246,7 +247,7 @@ enum v4l_camstates {
 struct cam_data {
        struct list_head cam_data_list;
 
-        struct semaphore busy_lock;     /* guard against SMP multithreading */
+        struct mutex busy_lock;     /* guard against SMP multithreading */
        struct cpia_camera_ops *ops;    /* lowlevel driver operations */
        void *lowlevel_data;            /* private data for lowlevel driver */
        u8 *raw_image;                  /* buffer for raw image data */
@@ -261,7 +262,7 @@ struct cam_data {
        u8 mainsFreq;                   /* for flicker control */
 
                                /* proc interface */
-       struct semaphore param_lock;    /* params lock for this camera */
+       struct mutex param_lock;        /* params lock for this camera */
        struct cam_params params;       /* camera settings */
        struct proc_dir_entry *proc_entry;      /* /proc/cpia/videoX */
        
diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig
new file mode 100644 (file)
index 0000000..513cc09
--- /dev/null
@@ -0,0 +1,9 @@
+config VIDEO_CPIA2
+       tristate "CPiA2 Video For Linux"
+       depends on VIDEO_DEV && USB
+       ---help---
+         This is the video4linux driver for cameras based on Vision's CPiA2
+         (Colour Processor Interface ASIC), such as the Digital Blue QX5
+         Microscope. If you have one of these cameras, say Y here
+
+         This driver is also available as a module (cpia2).
diff --git a/drivers/media/video/cpia2/Makefile b/drivers/media/video/cpia2/Makefile
new file mode 100644 (file)
index 0000000..828cf1b
--- /dev/null
@@ -0,0 +1,3 @@
+cpia2-objs     := cpia2_v4l.o cpia2_usb.o cpia2_core.o
+
+obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
new file mode 100644 (file)
index 0000000..95d3afa
--- /dev/null
@@ -0,0 +1,497 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPiA2 based video cameras.
+ *
+ *     This driver is modelled on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef __CPIA2_H__
+#define __CPIA2_H__
+
+#include <linux/version.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+
+#include "cpia2dev.h"
+#include "cpia2_registers.h"
+
+/* define for verbose debug output */
+//#define _CPIA2_DEBUG_
+
+#define CPIA2_MAJ_VER  2
+#define CPIA2_MIN_VER   0
+#define CPIA2_PATCH_VER        0
+
+/***
+ * Image defines
+ ***/
+#ifndef true
+#define true 1
+#define false 0
+#endif
+
+/*  Misc constants */
+#define ALLOW_CORRUPT 0                /* Causes collater to discard checksum */
+
+/* USB Transfer mode */
+#define XFER_ISOC 0
+#define XFER_BULK 1
+
+/* USB Alternates */
+#define USBIF_CMDONLY 0
+#define USBIF_BULK 1
+#define USBIF_ISO_1 2  /*  128 bytes/ms */
+#define USBIF_ISO_2 3  /*  384 bytes/ms */
+#define USBIF_ISO_3 4  /*  640 bytes/ms */
+#define USBIF_ISO_4 5  /*  768 bytes/ms */
+#define USBIF_ISO_5 6  /*  896 bytes/ms */
+#define USBIF_ISO_6 7  /* 1023 bytes/ms */
+
+/* Flicker Modes */
+#define NEVER_FLICKER   0
+#define ANTI_FLICKER_ON 1
+#define FLICKER_60      60
+#define FLICKER_50      50
+
+/* Debug flags */
+#define DEBUG_NONE          0
+#define DEBUG_REG           0x00000001
+#define DEBUG_DUMP_PATCH    0x00000002
+#define DEBUG_DUMP_REGS     0x00000004
+
+/***
+ * Video frame sizes
+ ***/
+enum {
+       VIDEOSIZE_VGA = 0,      /* 640x480 */
+       VIDEOSIZE_CIF,          /* 352x288 */
+       VIDEOSIZE_QVGA,         /* 320x240 */
+       VIDEOSIZE_QCIF,         /* 176x144 */
+       VIDEOSIZE_288_216,
+       VIDEOSIZE_256_192,
+       VIDEOSIZE_224_168,
+       VIDEOSIZE_192_144,
+};
+
+#define STV_IMAGE_CIF_ROWS    288
+#define STV_IMAGE_CIF_COLS    352
+
+#define STV_IMAGE_QCIF_ROWS   144
+#define STV_IMAGE_QCIF_COLS   176
+
+#define STV_IMAGE_VGA_ROWS    480
+#define STV_IMAGE_VGA_COLS    640
+
+#define STV_IMAGE_QVGA_ROWS   240
+#define STV_IMAGE_QVGA_COLS   320
+
+#define JPEG_MARKER_COM (1<<6) /* Comment segment */
+
+/***
+ * Enums
+ ***/
+/* Sensor types available with cpia2 asics */
+enum sensors {
+       CPIA2_SENSOR_410,
+       CPIA2_SENSOR_500
+};
+
+/* Asic types available in the CPiA2 architecture */
+#define  CPIA2_ASIC_672 0x67
+
+/* Device types (stv672, stv676, etc) */
+#define  DEVICE_STV_672   0x0001
+#define  DEVICE_STV_676   0x0002
+
+enum frame_status {
+       FRAME_EMPTY,
+       FRAME_READING,          /* In the process of being grabbed into */
+       FRAME_READY,            /* Ready to be read */
+       FRAME_ERROR,
+};
+
+/***
+ * Register access (for USB request byte)
+ ***/
+enum {
+       CAMERAACCESS_SYSTEM = 0,
+       CAMERAACCESS_VC,
+       CAMERAACCESS_VP,
+       CAMERAACCESS_IDATA
+};
+
+#define CAMERAACCESS_TYPE_BLOCK    0x00
+#define CAMERAACCESS_TYPE_RANDOM   0x04
+#define CAMERAACCESS_TYPE_MASK     0x08
+#define CAMERAACCESS_TYPE_REPEAT   0x0C
+
+#define TRANSFER_READ 0
+#define TRANSFER_WRITE 1
+
+#define DEFAULT_ALT   USBIF_ISO_6
+#define DEFAULT_BRIGHTNESS 0x46
+#define DEFAULT_CONTRAST 0x93
+#define DEFAULT_SATURATION 0x7f
+#define DEFAULT_TARGET_KB 0x30
+
+/* Power state */
+#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER
+#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER
+
+
+/********
+ * Commands
+ *******/
+enum {
+       CPIA2_CMD_NONE = 0,
+       CPIA2_CMD_GET_VERSION,
+       CPIA2_CMD_GET_PNP_ID,
+       CPIA2_CMD_GET_ASIC_TYPE,
+       CPIA2_CMD_GET_SENSOR,
+       CPIA2_CMD_GET_VP_DEVICE,
+       CPIA2_CMD_GET_VP_BRIGHTNESS,
+       CPIA2_CMD_SET_VP_BRIGHTNESS,
+       CPIA2_CMD_GET_CONTRAST,
+       CPIA2_CMD_SET_CONTRAST,
+       CPIA2_CMD_GET_VP_SATURATION,
+       CPIA2_CMD_SET_VP_SATURATION,
+       CPIA2_CMD_GET_VP_GPIO_DIRECTION,
+       CPIA2_CMD_SET_VP_GPIO_DIRECTION,
+       CPIA2_CMD_GET_VP_GPIO_DATA,
+       CPIA2_CMD_SET_VP_GPIO_DATA,
+       CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION,
+       CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+       CPIA2_CMD_GET_VC_MP_GPIO_DATA,
+       CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+       CPIA2_CMD_ENABLE_PACKET_CTRL,
+       CPIA2_CMD_GET_FLICKER_MODES,
+       CPIA2_CMD_SET_FLICKER_MODES,
+       CPIA2_CMD_RESET_FIFO,   /* clear fifo and enable stream block */
+       CPIA2_CMD_SET_HI_POWER,
+       CPIA2_CMD_SET_LOW_POWER,
+       CPIA2_CMD_CLEAR_V2W_ERR,
+       CPIA2_CMD_SET_USER_MODE,
+       CPIA2_CMD_GET_USER_MODE,
+       CPIA2_CMD_FRAMERATE_REQ,
+       CPIA2_CMD_SET_COMPRESSION_STATE,
+       CPIA2_CMD_GET_WAKEUP,
+       CPIA2_CMD_SET_WAKEUP,
+       CPIA2_CMD_GET_PW_CONTROL,
+       CPIA2_CMD_SET_PW_CONTROL,
+       CPIA2_CMD_GET_SYSTEM_CTRL,
+       CPIA2_CMD_SET_SYSTEM_CTRL,
+       CPIA2_CMD_GET_VP_SYSTEM_STATE,
+       CPIA2_CMD_GET_VP_SYSTEM_CTRL,
+       CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+       CPIA2_CMD_GET_VP_EXP_MODES,
+       CPIA2_CMD_SET_VP_EXP_MODES,
+       CPIA2_CMD_GET_DEVICE_CONFIG,
+       CPIA2_CMD_SET_DEVICE_CONFIG,
+       CPIA2_CMD_SET_SERIAL_ADDR,
+       CPIA2_CMD_SET_SENSOR_CR1,
+       CPIA2_CMD_GET_VC_CONTROL,
+       CPIA2_CMD_SET_VC_CONTROL,
+       CPIA2_CMD_SET_TARGET_KB,
+       CPIA2_CMD_SET_DEF_JPEG_OPT,
+       CPIA2_CMD_REHASH_VP4,
+       CPIA2_CMD_GET_USER_EFFECTS,
+       CPIA2_CMD_SET_USER_EFFECTS
+};
+
+enum user_cmd {
+       COMMAND_NONE = 0x00000001,
+       COMMAND_SET_FPS = 0x00000002,
+       COMMAND_SET_COLOR_PARAMS = 0x00000004,
+       COMMAND_GET_COLOR_PARAMS = 0x00000008,
+       COMMAND_SET_FORMAT = 0x00000010,        /* size, etc */
+       COMMAND_SET_FLICKER = 0x00000020
+};
+
+/***
+ * Some defines specific to the 676 chip
+ ***/
+#define CAMACC_CIF      0x01
+#define CAMACC_VGA      0x02
+#define CAMACC_QCIF     0x04
+#define CAMACC_QVGA     0x08
+
+
+struct cpia2_register {
+       u8 index;
+       u8 value;
+};
+
+struct cpia2_reg_mask {
+       u8 index;
+       u8 and_mask;
+       u8 or_mask;
+       u8 fill;
+};
+
+struct cpia2_command {
+       u32 command;
+       u8 req_mode;            /* (Block or random) | registerBank */
+       u8 reg_count;
+       u8 direction;
+       u8 start;
+       union reg_types {
+               struct cpia2_register registers[32];
+               struct cpia2_reg_mask masks[16];
+               u8 block_data[64];
+               u8 *patch_data; /* points to function defined block */
+       } buffer;
+};
+
+struct camera_params {
+       struct {
+               u8 firmware_revision_hi; /* For system register set (bank 0) */
+               u8 firmware_revision_lo;
+               u8 asic_id;     /* Video Compressor set (bank 1) */
+               u8 asic_rev;
+               u8 vp_device_hi;        /* Video Processor set (bank 2) */
+               u8 vp_device_lo;
+               u8 sensor_flags;
+               u8 sensor_rev;
+       } version;
+
+       struct {
+               u32 device_type;     /* enumerated from vendor/product ids.
+                                     * Currently, either STV_672 or STV_676 */
+               u16 vendor;
+               u16 product;
+               u16 device_revision;
+       } pnp_id;
+
+       struct {
+               u8 brightness;  /* CPIA2_VP_EXPOSURE_TARGET */
+               u8 contrast;    /* Note: this is CPIA2_VP_YRANGE */
+               u8 saturation;  /*  CPIA2_VP_SATURATION */
+       } color_params;
+
+       struct {
+               u8 cam_register;
+               u8 flicker_mode_req;    /* 1 if flicker on, else never flicker */
+               int mains_frequency;
+       } flicker_control;
+
+       struct {
+               u8 jpeg_options;
+               u8 creep_period;
+               u8 user_squeeze;
+               u8 inhibit_htables;
+       } compression;
+
+       struct {
+               u8 ohsize;      /* output image size */
+               u8 ovsize;
+               u8 hcrop;       /* cropping start_pos/4 */
+               u8 vcrop;
+               u8 hphase;      /* scaling registers */
+               u8 vphase;
+               u8 hispan;
+               u8 vispan;
+               u8 hicrop;
+               u8 vicrop;
+               u8 hifraction;
+               u8 vifraction;
+       } image_size;
+
+       struct {
+               int width;      /* actual window width */
+               int height;     /* actual window height */
+       } roi;
+
+       struct {
+               u8 video_mode;
+               u8 frame_rate;
+               u8 video_size;  /* Not a register, just a convenience for cropped sizes */
+               u8 gpio_direction;
+               u8 gpio_data;
+               u8 system_ctrl;
+               u8 system_state;
+               u8 lowlight_boost;      /* Bool: 0 = off, 1 = on */
+               u8 device_config;
+               u8 exposure_modes;
+               u8 user_effects;
+       } vp_params;
+
+       struct {
+               u8 pw_control;
+               u8 wakeup;
+               u8 vc_control;
+               u8 vc_mp_direction;
+               u8 vc_mp_data;
+               u8 target_kb;
+       } vc_params;
+
+       struct {
+               u8 power_mode;
+               u8 system_ctrl;
+               u8 stream_mode; /* This is the current alternate for usb drivers */
+               u8 allow_corrupt;
+       } camera_state;
+};
+
+#define NUM_SBUF    2
+
+struct cpia2_sbuf {
+       char *data;
+       struct urb *urb;
+};
+
+struct framebuf {
+       struct timeval timestamp;
+       unsigned long seq;
+       int num;
+       int length;
+       int max_length;
+       volatile enum frame_status status;
+       u8 *data;
+       struct framebuf *next;
+};
+
+struct cpia2_fh {
+       enum v4l2_priority prio;
+       u8 mmapped;
+};
+
+struct camera_data {
+       /* locks */
+       struct semaphore busy_lock;     /* guard against SMP multithreading */
+       struct v4l2_prio_state prio;
+
+       /* camera status */
+       volatile int present;   /* Is the camera still present? */
+       int open_count;         /* # of process that have camera open */
+       int first_image_seen;
+       u8 mains_freq;          /* for flicker control */
+       enum sensors sensor_type;
+       u8 flush;
+       u8 mmapped;
+       int streaming;          /* 0 = no, 1 = yes */
+       int xfer_mode;          /* XFER_BULK or XFER_ISOC */
+       struct camera_params params;    /* camera settings */
+
+       /* v4l */
+       int video_size;                 /* VIDEO_SIZE_ */
+       struct video_device *vdev;      /* v4l videodev */
+       struct video_picture vp;        /* v4l camera settings */
+       struct video_window vw;         /* v4l capture area */
+       __u32 pixelformat;       /* Format fourcc      */
+
+       /* USB */
+       struct usb_device *dev;
+       unsigned char iface;
+       unsigned int cur_alt;
+       unsigned int old_alt;
+       struct cpia2_sbuf sbuf[NUM_SBUF];       /* Double buffering */
+
+       wait_queue_head_t wq_stream;
+
+       /* Buffering */
+       u32 frame_size;
+       int num_frames;
+       unsigned long frame_count;
+       u8 *frame_buffer;       /* frame buffer data */
+       struct framebuf *buffers;
+       struct framebuf * volatile curbuff;
+       struct framebuf *workbuff;
+
+       /* MJPEG Extension */
+       int APPn;               /* Number of APP segment to be written, must be 0..15 */
+       int APP_len;            /* Length of data in JPEG APPn segment */
+       char APP_data[60];      /* Data in the JPEG APPn segment. */
+
+       int COM_len;            /* Length of data in JPEG COM segment */
+       char COM_data[60];      /* Data in JPEG COM segment */
+};
+
+/* v4l */
+int cpia2_register_camera(struct camera_data *cam);
+void cpia2_unregister_camera(struct camera_data *cam);
+
+/* core */
+int cpia2_reset_camera(struct camera_data *cam);
+int cpia2_set_low_power(struct camera_data *cam);
+void cpia2_dbg_dump_registers(struct camera_data *cam);
+int cpia2_match_video_size(int width, int height);
+void cpia2_set_camera_state(struct camera_data *cam);
+void cpia2_save_camera_state(struct camera_data *cam);
+void cpia2_set_color_params(struct camera_data *cam);
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value);
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value);
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value);
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode);
+void cpia2_set_format(struct camera_data *cam);
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
+int cpia2_do_command(struct camera_data *cam,
+                    unsigned int command,
+                    unsigned char direction, unsigned char param);
+struct camera_data *cpia2_init_camera_struct(void);
+int cpia2_init_camera(struct camera_data *cam);
+int cpia2_allocate_buffers(struct camera_data *cam);
+void cpia2_free_buffers(struct camera_data *cam);
+long cpia2_read(struct camera_data *cam,
+               char *buf, unsigned long count, int noblock);
+unsigned int cpia2_poll(struct camera_data *cam,
+                       struct file *filp, poll_table *wait);
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma);
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val);
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val);
+int cpia2_set_target_kb(struct camera_data *cam, unsigned char value);
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting);
+int cpia2_set_fps(struct camera_data *cam, int framerate);
+
+/* usb */
+int cpia2_usb_init(void);
+void cpia2_usb_cleanup(void);
+int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers,
+                          u8 request, u8 start, u8 count, u8 direction);
+int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate);
+int cpia2_usb_stream_stop(struct camera_data *cam);
+int cpia2_usb_stream_pause(struct camera_data *cam);
+int cpia2_usb_stream_resume(struct camera_data *cam);
+int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
+                                        unsigned int alt);
+
+
+/* ----------------------- debug functions ---------------------- */
+#ifdef _CPIA2_DEBUG_
+#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args)
+#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args)
+#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args)
+#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args)
+#else
+#define ALOG(fmt,args...) printk(fmt,##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args)
+#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args)
+#define DBG(fmn,args...) do {} while(0)
+#endif
+/* No function or lineno, for shorter lines */
+#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args)
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
new file mode 100644 (file)
index 0000000..5dfb242
--- /dev/null
@@ -0,0 +1,2525 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_core.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *             Alan Cox <alan@redhat.com>
+ *
+ ****************************************************************************/
+
+#include "cpia2.h"
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+//#define _CPIA2_DEBUG_
+
+#include "cpia2patch.h"
+
+#ifdef _CPIA2_DEBUG_
+
+static const char *block_name[] = {
+       "System",
+       "VC",
+       "VP",
+       "IDATA"
+};
+#endif
+
+static unsigned int debugs_on = 0;//DEBUG_REG;
+
+
+/******************************************************************************
+ *
+ *  Forward Declarations
+ *
+ *****************************************************************************/
+static int apply_vp_patch(struct camera_data *cam);
+static int set_default_user_mode(struct camera_data *cam);
+static int set_vw_size(struct camera_data *cam, int size);
+static int configure_sensor(struct camera_data *cam,
+                           int reqwidth, int reqheight);
+static int config_sensor_410(struct camera_data *cam,
+                           int reqwidth, int reqheight);
+static int config_sensor_500(struct camera_data *cam,
+                           int reqwidth, int reqheight);
+static int set_all_properties(struct camera_data *cam);
+static void get_color_params(struct camera_data *cam);
+static void wake_system(struct camera_data *cam);
+static void set_lowlight_boost(struct camera_data *cam);
+static void reset_camera_struct(struct camera_data *cam);
+static int cpia2_set_high_power(struct camera_data *cam);
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+       unsigned long kva, ret;
+
+       kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+       kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+       ret = __pa(kva);
+       return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       /* Round it off to PAGE_SIZE */
+       size = PAGE_ALIGN(size);
+
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size);   /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+
+       while ((long)size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       size = PAGE_ALIGN(size);
+
+       adr = (unsigned long) mem;
+       while ((long)size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_do_command
+ *
+ *  Send an arbitrary command to the camera.  For commands that read from
+ *  the camera, copy the buffers into the proper param structures.
+ *****************************************************************************/
+int cpia2_do_command(struct camera_data *cam,
+                    u32 command, u8 direction, u8 param)
+{
+       int retval = 0;
+       struct cpia2_command cmd;
+       unsigned int device = cam->params.pnp_id.device_type;
+
+       cmd.command = command;
+       cmd.reg_count = 2;      /* default */
+       cmd.direction = direction;
+
+       /***
+        * Set up the command.
+        ***/
+       switch (command) {
+       case CPIA2_CMD_GET_VERSION:
+               cmd.req_mode =
+                   CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+               cmd.start = CPIA2_SYSTEM_DEVICE_HI;
+               break;
+       case CPIA2_CMD_GET_PNP_ID:
+               cmd.req_mode =
+                   CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+               cmd.reg_count = 8;
+               cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI;
+               break;
+       case CPIA2_CMD_GET_ASIC_TYPE:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+               cmd.start = CPIA2_VC_ASIC_ID;
+               break;
+       case CPIA2_CMD_GET_SENSOR:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.start = CPIA2_VP_SENSOR_FLAGS;
+               break;
+       case CPIA2_CMD_GET_VP_DEVICE:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.start = CPIA2_VP_DEVICEH;
+               break;
+       case CPIA2_CMD_SET_VP_BRIGHTNESS:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VP_BRIGHTNESS:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               if (device == DEVICE_STV_672)
+                       cmd.start = CPIA2_VP4_EXPOSURE_TARGET;
+               else
+                       cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+               break;
+       case CPIA2_CMD_SET_CONTRAST:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_CONTRAST:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_YRANGE;
+               break;
+       case CPIA2_CMD_SET_VP_SATURATION:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VP_SATURATION:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               if (device == DEVICE_STV_672)
+                       cmd.start = CPIA2_VP_SATURATION;
+               else
+                       cmd.start = CPIA2_VP5_MCUVSATURATION;
+               break;
+       case CPIA2_CMD_SET_VP_GPIO_DATA:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VP_GPIO_DATA:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_GPIO_DATA;
+               break;
+       case CPIA2_CMD_SET_VP_GPIO_DIRECTION:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_GPIO_DIRECTION;
+               break;
+       case CPIA2_CMD_SET_VC_MP_GPIO_DATA:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VC_MP_DATA;
+               break;
+       case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VC_MP_DIR;
+               break;
+       case CPIA2_CMD_ENABLE_PACKET_CTRL:
+               cmd.req_mode =
+                   CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+               cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL;
+               cmd.reg_count = 1;
+               cmd.buffer.block_data[0] = param;
+               break;
+       case CPIA2_CMD_SET_FLICKER_MODES:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_FLICKER_MODES:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_FLICKER_MODES;
+               break;
+       case CPIA2_CMD_RESET_FIFO:      /* clear fifo and enable stream block */
+               cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+               cmd.reg_count = 2;
+               cmd.start = 0;
+               cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+               cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+                   CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+               cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+               cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+                   CPIA2_VC_ST_CTRL_DST_USB |
+                   CPIA2_VC_ST_CTRL_EOF_DETECT |
+                   CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+               break;
+       case CPIA2_CMD_SET_HI_POWER:
+               cmd.req_mode =
+                   CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+               cmd.reg_count = 2;
+               cmd.buffer.registers[0].index =
+                   CPIA2_SYSTEM_SYSTEM_CONTROL;
+               cmd.buffer.registers[1].index =
+                   CPIA2_SYSTEM_SYSTEM_CONTROL;
+               cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+               cmd.buffer.registers[1].value =
+                   CPIA2_SYSTEM_CONTROL_HIGH_POWER;
+               break;
+       case CPIA2_CMD_SET_LOW_POWER:
+               cmd.req_mode =
+                   CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+               cmd.buffer.block_data[0] = 0;
+               break;
+       case CPIA2_CMD_CLEAR_V2W_ERR:
+               cmd.req_mode =
+                   CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+               cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
+               break;
+       case CPIA2_CMD_SET_USER_MODE:   /* Then fall through */
+               cmd.buffer.block_data[0] = param;
+       case CPIA2_CMD_GET_USER_MODE:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               if (device == DEVICE_STV_672)
+                       cmd.start = CPIA2_VP4_USER_MODE;
+               else
+                       cmd.start = CPIA2_VP5_USER_MODE;
+               break;
+       case CPIA2_CMD_FRAMERATE_REQ:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               if (device == DEVICE_STV_672)
+                       cmd.start = CPIA2_VP4_FRAMERATE_REQUEST;
+               else
+                       cmd.start = CPIA2_VP5_FRAMERATE_REQUEST;
+               cmd.buffer.block_data[0] = param;
+               break;
+       case CPIA2_CMD_SET_WAKEUP:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_WAKEUP:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VC_WAKEUP;
+               break;
+       case CPIA2_CMD_SET_PW_CONTROL:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_PW_CONTROL:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VC_PW_CTRL;
+               break;
+       case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_SYSTEMSTATE;
+               break;
+       case CPIA2_CMD_SET_SYSTEM_CTRL:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_SYSTEM_CTRL:
+               cmd.req_mode =
+                   CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
+               break;
+       case CPIA2_CMD_SET_VP_SYSTEM_CTRL:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_SYSTEMCTRL;
+               break;
+       case CPIA2_CMD_SET_VP_EXP_MODES:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VP_EXP_MODES:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_EXPOSURE_MODES;
+               break;
+       case CPIA2_CMD_SET_DEVICE_CONFIG:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_DEVICE_CONFIG:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_DEVICE_CONFIG;
+               break;
+       case CPIA2_CMD_SET_SERIAL_ADDR:
+               cmd.buffer.block_data[0] = param;
+               cmd.req_mode =
+                   CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR;
+               break;
+       case CPIA2_CMD_SET_SENSOR_CR1:
+               cmd.buffer.block_data[0] = param;
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_SENSOR_CR1;
+               break;
+       case CPIA2_CMD_SET_VC_CONTROL:
+               cmd.buffer.block_data[0] = param;       /* Then fall through */
+       case CPIA2_CMD_GET_VC_CONTROL:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VC_VC_CTRL;
+               break;
+       case CPIA2_CMD_SET_TARGET_KB:
+               cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+               cmd.reg_count = 1;
+               cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB;
+               cmd.buffer.registers[0].value = param;
+               break;
+       case CPIA2_CMD_SET_DEF_JPEG_OPT:
+               cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+               cmd.reg_count = 4;
+               cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT;
+               cmd.buffer.registers[0].value =
+                   CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE;
+               cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE;
+               cmd.buffer.registers[1].value = 20;
+               cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD;
+               cmd.buffer.registers[2].value = 2;
+               cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT;
+               cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+               break;
+       case CPIA2_CMD_REHASH_VP4:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP_REHASH_VALUES;
+               cmd.buffer.block_data[0] = param;
+               break;
+       case CPIA2_CMD_SET_USER_EFFECTS:  /* Note: Be careful with this as
+                                            this register can also affect
+                                            flicker modes */
+               cmd.buffer.block_data[0] = param;      /* Then fall through */
+       case CPIA2_CMD_GET_USER_EFFECTS:
+               cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+               cmd.reg_count = 1;
+               if (device == DEVICE_STV_672)
+                       cmd.start = CPIA2_VP4_USER_EFFECTS;
+               else
+                       cmd.start = CPIA2_VP5_USER_EFFECTS;
+               break;
+       default:
+               LOG("DoCommand received invalid command\n");
+               return -EINVAL;
+       }
+
+       retval = cpia2_send_command(cam, &cmd);
+       if (retval) {
+               return retval;
+       }
+
+       /***
+        * Now copy any results from a read into the appropriate param struct.
+        ***/
+       switch (command) {
+       case CPIA2_CMD_GET_VERSION:
+               cam->params.version.firmware_revision_hi =
+                   cmd.buffer.block_data[0];
+               cam->params.version.firmware_revision_lo =
+                   cmd.buffer.block_data[1];
+               break;
+       case CPIA2_CMD_GET_PNP_ID:
+               cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) |
+                                           cmd.buffer.block_data[1];
+               cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) |
+                                            cmd.buffer.block_data[3];
+               cam->params.pnp_id.device_revision =
+                       (cmd.buffer.block_data[4] << 8) |
+                       cmd.buffer.block_data[5];
+               if (cam->params.pnp_id.vendor == 0x553) {
+                       if (cam->params.pnp_id.product == 0x100) {
+                               cam->params.pnp_id.device_type = DEVICE_STV_672;
+                       } else if (cam->params.pnp_id.product == 0x140 ||
+                                  cam->params.pnp_id.product == 0x151) {
+                               cam->params.pnp_id.device_type = DEVICE_STV_676;
+                       }
+               }
+               break;
+       case CPIA2_CMD_GET_ASIC_TYPE:
+               cam->params.version.asic_id = cmd.buffer.block_data[0];
+               cam->params.version.asic_rev = cmd.buffer.block_data[1];
+               break;
+       case CPIA2_CMD_GET_SENSOR:
+               cam->params.version.sensor_flags = cmd.buffer.block_data[0];
+               cam->params.version.sensor_rev = cmd.buffer.block_data[1];
+               break;
+       case CPIA2_CMD_GET_VP_DEVICE:
+               cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
+               cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
+               break;
+       case CPIA2_CMD_GET_VP_BRIGHTNESS:
+               cam->params.color_params.brightness = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_CONTRAST:
+               cam->params.color_params.contrast = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VP_SATURATION:
+               cam->params.color_params.saturation = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VP_GPIO_DATA:
+               cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
+               cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
+               cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
+               cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_FLICKER_MODES:
+               cam->params.flicker_control.cam_register =
+                       cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_WAKEUP:
+               cam->params.vc_params.wakeup = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_PW_CONTROL:
+               cam->params.vc_params.pw_control = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_SYSTEM_CTRL:
+               cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VP_SYSTEM_STATE:
+               cam->params.vp_params.system_state = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
+               cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VP_EXP_MODES:
+               cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_DEVICE_CONFIG:
+               cam->params.vp_params.device_config = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_VC_CONTROL:
+               cam->params.vc_params.vc_control = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_USER_MODE:
+               cam->params.vp_params.video_mode = cmd.buffer.block_data[0];
+               break;
+       case CPIA2_CMD_GET_USER_EFFECTS:
+               cam->params.vp_params.user_effects = cmd.buffer.block_data[0];
+               break;
+       default:
+               break;
+       }
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_send_command
+ *
+ *****************************************************************************/
+int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
+{
+       u8 count;
+       u8 start;
+       u8 block_index;
+       u8 *buffer;
+       int retval;
+       const char* dir;
+
+       if (cmd->direction == TRANSFER_WRITE) {
+               dir = "Write";
+       } else {
+               dir = "Read";
+       }
+
+       block_index = cmd->req_mode & 0x03;
+
+       switch (cmd->req_mode & 0x0c) {
+       case CAMERAACCESS_TYPE_RANDOM:
+               count = cmd->reg_count * sizeof(struct cpia2_register);
+               start = 0;
+               buffer = (u8 *) & cmd->buffer;
+               if (debugs_on & DEBUG_REG)
+                       DBG("%s Random: Register block %s\n", dir,
+                           block_name[block_index]);
+               break;
+       case CAMERAACCESS_TYPE_BLOCK:
+               count = cmd->reg_count;
+               start = cmd->start;
+               buffer = cmd->buffer.block_data;
+               if (debugs_on & DEBUG_REG)
+                       DBG("%s Block: Register block %s\n", dir,
+                           block_name[block_index]);
+               break;
+       case CAMERAACCESS_TYPE_MASK:
+               count = cmd->reg_count * sizeof(struct cpia2_reg_mask);
+               start = 0;
+               buffer = (u8 *) & cmd->buffer;
+               if (debugs_on & DEBUG_REG)
+                       DBG("%s Mask: Register block %s\n", dir,
+                           block_name[block_index]);
+               break;
+       case CAMERAACCESS_TYPE_REPEAT:  /* For patch blocks only */
+               count = cmd->reg_count;
+               start = cmd->start;
+               buffer = cmd->buffer.block_data;
+               if (debugs_on & DEBUG_REG)
+                       DBG("%s Repeat: Register block %s\n", dir,
+                           block_name[block_index]);
+               break;
+       default:
+               LOG("%s: invalid request mode\n",__FUNCTION__);
+               return -EINVAL;
+       }
+
+       retval = cpia2_usb_transfer_cmd(cam,
+                                       buffer,
+                                       cmd->req_mode,
+                                       start, count, cmd->direction);
+#ifdef _CPIA2_DEBUG_
+       if (debugs_on & DEBUG_REG) {
+               int i;
+               for (i = 0; i < cmd->reg_count; i++) {
+                       if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK)
+                               KINFO("%s Block: [0x%02X] = 0x%02X\n",
+                                   dir, start + i, buffer[i]);
+                       if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM)
+                               KINFO("%s Random: [0x%02X] = 0x%02X\n",
+                                   dir, cmd->buffer.registers[i].index,
+                                   cmd->buffer.registers[i].value);
+               }
+       }
+#endif
+
+       return retval;
+};
+
+/*************
+ * Functions to implement camera functionality
+ *************/
+/******************************************************************************
+ *
+ *  cpia2_get_version_info
+ *
+ *****************************************************************************/
+static void cpia2_get_version_info(struct camera_data *cam)
+{
+       cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0);
+       cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0);
+       cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0);
+       cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0);
+       cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_reset_camera
+ *
+ *  Called at least during the open process, sets up initial params.
+ *****************************************************************************/
+int cpia2_reset_camera(struct camera_data *cam)
+{
+       u8 tmp_reg;
+       int retval = 0;
+       int i;
+       struct cpia2_command cmd;
+
+       /***
+        * VC setup
+        ***/
+       retval = configure_sensor(cam,
+                                 cam->params.roi.width,
+                                 cam->params.roi.height);
+       if (retval < 0) {
+               ERR("Couldn't configure sensor, error=%d\n", retval);
+               return retval;
+       }
+
+       /* Clear FIFO and route/enable stream block */
+       cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+       cmd.direction = TRANSFER_WRITE;
+       cmd.reg_count = 2;
+       cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
+       cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
+               CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
+       cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
+       cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
+               CPIA2_VC_ST_CTRL_DST_USB |
+               CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE;
+
+       cpia2_send_command(cam, &cmd);
+
+       cpia2_set_high_power(cam);
+
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+               /* Enable button notification */
+               cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
+               cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL;
+               cmd.buffer.registers[0].value =
+                       CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX;
+               cmd.reg_count = 1;
+               cpia2_send_command(cam, &cmd);
+       }
+
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+               retval = apply_vp_patch(cam);
+
+       /* wait for vp to go to sleep */
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+
+       /***
+        * If this is a 676, apply VP5 fixes before we start streaming
+        ***/
+       if (cam->params.pnp_id.device_type == DEVICE_STV_676) {
+               cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+
+               /* The following writes improve the picture */
+               cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL;
+               cmd.buffer.registers[0].value = 0; /* reduce from the default
+                                                   * rec 601 pedestal of 16 */
+               cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE;
+               cmd.buffer.registers[1].value = 0x92; /* increase from 100% to
+                                                      * (256/256 - 31) to fill
+                                                      * available range */
+               cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING;
+               cmd.buffer.registers[2].value = 0xFF; /* Increase from the
+                                                      * default rec 601 ceiling
+                                                      * of 240 */
+               cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION;
+               cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec
+                                                      * 601 100% level (128)
+                                                      * to 145-192 */
+               cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP;
+               cmd.buffer.registers[4].value = 0x80;  /* Inhibit the
+                                                       * anti-flicker */
+
+               /* The following 4 writes are a fix to allow QVGA to work at 30 fps */
+               cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H;
+               cmd.buffer.registers[5].value = 0x01;
+               cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L;
+               cmd.buffer.registers[6].value = 0xE3;
+               cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA;
+               cmd.buffer.registers[7].value = 0x02;
+               cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA;
+               cmd.buffer.registers[8].value = 0xFC;
+
+               cmd.direction = TRANSFER_WRITE;
+               cmd.reg_count = 9;
+
+               cpia2_send_command(cam, &cmd);
+       }
+
+       /* Activate all settings and start the data stream */
+       /* Set user mode */
+       set_default_user_mode(cam);
+
+       /* Give VP time to wake up */
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(100 * HZ / 1000);      /* wait for 100 msecs */
+
+       set_all_properties(cam);
+
+       cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+       DBG("After SetAllProperties(cam), user mode is 0x%0X\n",
+           cam->params.vp_params.video_mode);
+
+       /***
+        * Set audio regulator off.  This and the code to set the compresison
+        * state are too complex to form a CPIA2_CMD_, and seem to be somewhat
+        * intertwined.  This stuff came straight from the windows driver.
+        ***/
+       /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */
+       cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+       tmp_reg = cam->params.vp_params.system_ctrl;
+       cmd.buffer.registers[0].value = tmp_reg &
+               (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF));
+
+       cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+       cmd.buffer.registers[1].value = cam->params.vp_params.device_config |
+                                       CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE;
+       cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL;
+       cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG;
+       cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+       cmd.reg_count = 2;
+       cmd.direction = TRANSFER_WRITE;
+       cmd.start = 0;
+       cpia2_send_command(cam, &cmd);
+
+       /* Set the correct I2C address in the CPiA-2 system register */
+       cpia2_do_command(cam,
+                        CPIA2_CMD_SET_SERIAL_ADDR,
+                        TRANSFER_WRITE,
+                        CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR);
+
+       /* Now have sensor access - set bit to turn the audio regulator off */
+       cpia2_do_command(cam,
+                        CPIA2_CMD_SET_SENSOR_CR1,
+                        TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR);
+
+       /* Set the correct I2C address in the CPiA-2 system register */
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+               cpia2_do_command(cam,
+                                CPIA2_CMD_SET_SERIAL_ADDR,
+                                TRANSFER_WRITE,
+                                CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88
+       else
+               cpia2_do_command(cam,
+                                CPIA2_CMD_SET_SERIAL_ADDR,
+                                TRANSFER_WRITE,
+                                CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a
+
+       /* increase signal drive strength */
+       if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+               cpia2_do_command(cam,
+                                CPIA2_CMD_SET_VP_EXP_MODES,
+                                TRANSFER_WRITE,
+                                CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP);
+
+       /* Start autoexposure */
+       cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
+       cmd.buffer.registers[0].value = cam->params.vp_params.device_config &
+                                 (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF);
+
+       cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
+       cmd.buffer.registers[1].value =
+           cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL;
+
+       cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG;
+       cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL;
+       cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
+       cmd.reg_count = 2;
+       cmd.direction = TRANSFER_WRITE;
+
+       cpia2_send_command(cam, &cmd);
+
+       /* Set compression state */
+       cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0);
+       if (cam->params.compression.inhibit_htables) {
+               tmp_reg = cam->params.vc_params.vc_control |
+                         CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+       } else  {
+               tmp_reg = cam->params.vc_params.vc_control &
+                         ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
+       }
+       cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+       /* Set target size (kb) on vc */
+       cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
+                        TRANSFER_WRITE, cam->params.vc_params.target_kb);
+
+       /* Wiggle VC Reset */
+       /***
+        * First read and wait a bit.
+        ***/
+       for (i = 0; i < 50; i++) {
+               cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL,
+                                TRANSFER_READ, 0);
+       }
+
+       tmp_reg = cam->params.vc_params.pw_control;
+       tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N;
+
+       cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+       tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N;
+       cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
+
+       cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0);
+
+       cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
+       DBG("After VC RESET, user mode is 0x%0X\n",
+           cam->params.vp_params.video_mode);
+
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_high_power
+ *
+ *****************************************************************************/
+static int cpia2_set_high_power(struct camera_data *cam)
+{
+       int i;
+       for (i = 0; i <= 50; i++) {
+               /* Read system status */
+               cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0);
+
+               /* If there is an error, clear it */
+               if(cam->params.camera_state.system_ctrl &
+                  CPIA2_SYSTEM_CONTROL_V2W_ERR)
+                       cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR,
+                                        TRANSFER_WRITE, 0);
+
+               /* Try to set high power mode */
+               cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL,
+                                TRANSFER_WRITE, 1);
+
+               /* Try to read something in VP to check if everything is awake */
+               cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE,
+                                TRANSFER_READ, 0);
+               if (cam->params.vp_params.system_state &
+                   CPIA2_VP_SYSTEMSTATE_HK_ALIVE) {
+                       break;
+               } else if (i == 50) {
+                       cam->params.camera_state.power_mode = LO_POWER_MODE;
+                       ERR("Camera did not wake up\n");
+                       return -EIO;
+               }
+       }
+
+       DBG("System now in high power state\n");
+       cam->params.camera_state.power_mode = HI_POWER_MODE;
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_low_power
+ *
+ *****************************************************************************/
+int cpia2_set_low_power(struct camera_data *cam)
+{
+       cam->params.camera_state.power_mode = LO_POWER_MODE;
+       cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0);
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  apply_vp_patch
+ *
+ *****************************************************************************/
+static int apply_vp_patch(struct camera_data *cam)
+{
+       int i, j;
+       struct cpia2_command cmd;
+
+       cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP;
+       cmd.direction = TRANSFER_WRITE;
+
+       for (i = 0; i < PATCH_DATA_SIZE; i++) {
+               for (j = 0; j < patch_data[i].count; j++) {
+                       cmd.buffer.block_data[j] = patch_data[i].data[j];
+               }
+
+               cmd.start = patch_data[i].reg;
+               cmd.reg_count = patch_data[i].count;
+               cpia2_send_command(cam, &cmd);
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  set_default_user_mode
+ *
+ *****************************************************************************/
+static int set_default_user_mode(struct camera_data *cam)
+{
+       unsigned char user_mode;
+       unsigned char frame_rate;
+       int width = cam->params.roi.width;
+       int height = cam->params.roi.height;
+
+       switch (cam->params.version.sensor_flags) {
+       case CPIA2_VP_SENSOR_FLAGS_404:
+       case CPIA2_VP_SENSOR_FLAGS_407:
+       case CPIA2_VP_SENSOR_FLAGS_409:
+       case CPIA2_VP_SENSOR_FLAGS_410:
+               if ((width > STV_IMAGE_QCIF_COLS)
+                   || (height > STV_IMAGE_QCIF_ROWS)) {
+                       user_mode = CPIA2_VP_USER_MODE_CIF;
+               } else {
+                       user_mode = CPIA2_VP_USER_MODE_QCIFDS;
+               }
+               frame_rate = CPIA2_VP_FRAMERATE_30;
+               break;
+       case CPIA2_VP_SENSOR_FLAGS_500:
+               if ((width > STV_IMAGE_CIF_COLS)
+                   || (height > STV_IMAGE_CIF_ROWS)) {
+                       user_mode = CPIA2_VP_USER_MODE_VGA;
+               } else {
+                       user_mode = CPIA2_VP_USER_MODE_QVGADS;
+               }
+               if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+                       frame_rate = CPIA2_VP_FRAMERATE_15;
+               else
+                       frame_rate = CPIA2_VP_FRAMERATE_30;
+               break;
+       default:
+               LOG("%s: Invalid sensor flag value 0x%0X\n",__FUNCTION__,
+                   cam->params.version.sensor_flags);
+               return -EINVAL;
+       }
+
+       DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n",
+           cam->params.version.sensor_flags, user_mode, frame_rate);
+       cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE,
+                        user_mode);
+       if(cam->params.vp_params.frame_rate > 0 &&
+          frame_rate > cam->params.vp_params.frame_rate)
+               frame_rate = cam->params.vp_params.frame_rate;
+
+       cpia2_set_fps(cam, frame_rate);
+
+//     if (cam->params.pnp_id.device_type == DEVICE_STV_676)
+//             cpia2_do_command(cam,
+//                              CPIA2_CMD_SET_VP_SYSTEM_CTRL,
+//                              TRANSFER_WRITE,
+//                              CPIA2_VP_SYSTEMCTRL_HK_CONTROL |
+//                              CPIA2_VP_SYSTEMCTRL_POWER_CONTROL);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_match_video_size
+ *
+ *  return the best match, where 'best' is as always
+ *  the largest that is not bigger than what is requested.
+ *****************************************************************************/
+int cpia2_match_video_size(int width, int height)
+{
+       if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS)
+               return VIDEOSIZE_VGA;
+
+       if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS)
+               return VIDEOSIZE_CIF;
+
+       if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS)
+               return VIDEOSIZE_QVGA;
+
+       if (width >= 288 && height >= 216)
+               return VIDEOSIZE_288_216;
+
+       if (width >= 256 && height >= 192)
+               return VIDEOSIZE_256_192;
+
+       if (width >= 224 && height >= 168)
+               return VIDEOSIZE_224_168;
+
+       if (width >= 192 && height >= 144)
+               return VIDEOSIZE_192_144;
+
+       if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS)
+               return VIDEOSIZE_QCIF;
+
+       return -1;
+}
+
+/******************************************************************************
+ *
+ *  SetVideoSize
+ *
+ *****************************************************************************/
+static int set_vw_size(struct camera_data *cam, int size)
+{
+       int retval = 0;
+
+       cam->params.vp_params.video_size = size;
+
+       switch (size) {
+       case VIDEOSIZE_VGA:
+               DBG("Setting size to VGA\n");
+               cam->params.roi.width = STV_IMAGE_VGA_COLS;
+               cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+               cam->vw.width = STV_IMAGE_VGA_COLS;
+               cam->vw.height = STV_IMAGE_VGA_ROWS;
+               break;
+       case VIDEOSIZE_CIF:
+               DBG("Setting size to CIF\n");
+               cam->params.roi.width = STV_IMAGE_CIF_COLS;
+               cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+               cam->vw.width = STV_IMAGE_CIF_COLS;
+               cam->vw.height = STV_IMAGE_CIF_ROWS;
+               break;
+       case VIDEOSIZE_QVGA:
+               DBG("Setting size to QVGA\n");
+               cam->params.roi.width = STV_IMAGE_QVGA_COLS;
+               cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
+               cam->vw.width = STV_IMAGE_QVGA_COLS;
+               cam->vw.height = STV_IMAGE_QVGA_ROWS;
+               break;
+       case VIDEOSIZE_288_216:
+               cam->params.roi.width = 288;
+               cam->params.roi.height = 216;
+               cam->vw.width = 288;
+               cam->vw.height = 216;
+               break;
+       case VIDEOSIZE_256_192:
+               cam->vw.width = 256;
+               cam->vw.height = 192;
+               cam->params.roi.width = 256;
+               cam->params.roi.height = 192;
+               break;
+       case VIDEOSIZE_224_168:
+               cam->vw.width = 224;
+               cam->vw.height = 168;
+               cam->params.roi.width = 224;
+               cam->params.roi.height = 168;
+               break;
+       case VIDEOSIZE_192_144:
+               cam->vw.width = 192;
+               cam->vw.height = 144;
+               cam->params.roi.width = 192;
+               cam->params.roi.height = 144;
+               break;
+       case VIDEOSIZE_QCIF:
+               DBG("Setting size to QCIF\n");
+               cam->params.roi.width = STV_IMAGE_QCIF_COLS;
+               cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
+               cam->vw.width = STV_IMAGE_QCIF_COLS;
+               cam->vw.height = STV_IMAGE_QCIF_ROWS;
+               break;
+       default:
+               retval = -EINVAL;
+       }
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  configure_sensor
+ *
+ *****************************************************************************/
+static int configure_sensor(struct camera_data *cam,
+                           int req_width, int req_height)
+{
+       int retval;
+
+       switch (cam->params.version.sensor_flags) {
+       case CPIA2_VP_SENSOR_FLAGS_404:
+       case CPIA2_VP_SENSOR_FLAGS_407:
+       case CPIA2_VP_SENSOR_FLAGS_409:
+       case CPIA2_VP_SENSOR_FLAGS_410:
+               retval = config_sensor_410(cam, req_width, req_height);
+               break;
+       case CPIA2_VP_SENSOR_FLAGS_500:
+               retval = config_sensor_500(cam, req_width, req_height);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  config_sensor_410
+ *
+ *****************************************************************************/
+static int config_sensor_410(struct camera_data *cam,
+                           int req_width, int req_height)
+{
+       struct cpia2_command cmd;
+       int i = 0;
+       int image_size;
+       int image_type;
+       int width = req_width;
+       int height = req_height;
+
+       /***
+        *  Make sure size doesn't exceed CIF.
+        ***/
+       if (width > STV_IMAGE_CIF_COLS)
+               width = STV_IMAGE_CIF_COLS;
+       if (height > STV_IMAGE_CIF_ROWS)
+               height = STV_IMAGE_CIF_ROWS;
+
+       image_size = cpia2_match_video_size(width, height);
+
+       DBG("Config 410: width = %d, height = %d\n", width, height);
+       DBG("Image size returned is %d\n", image_size);
+       if (image_size >= 0) {
+               set_vw_size(cam, image_size);
+               width = cam->params.roi.width;
+               height = cam->params.roi.height;
+
+               DBG("After set_vw_size(), width = %d, height = %d\n",
+                   width, height);
+               if (width <= 176 && height <= 144) {
+                       DBG("image type = VIDEOSIZE_QCIF\n");
+                       image_type = VIDEOSIZE_QCIF;
+               }
+               else if (width <= 320 && height <= 240) {
+                       DBG("image type = VIDEOSIZE_QVGA\n");
+                       image_type = VIDEOSIZE_QVGA;
+               }
+               else {
+                       DBG("image type = VIDEOSIZE_CIF\n");
+                       image_type = VIDEOSIZE_CIF;
+               }
+       } else {
+               ERR("ConfigSensor410 failed\n");
+               return -EINVAL;
+       }
+
+       cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+       cmd.direction = TRANSFER_WRITE;
+
+       /* VC Format */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+       if (image_type == VIDEOSIZE_CIF) {
+               cmd.buffer.registers[i++].value =
+                   (u8) (CPIA2_VC_VC_FORMAT_UFIRST |
+                         CPIA2_VC_VC_FORMAT_SHORTLINE);
+       } else {
+               cmd.buffer.registers[i++].value =
+                   (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+       }
+
+       /* VC Clocks */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+       if (image_type == VIDEOSIZE_QCIF) {
+               if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+                       cmd.buffer.registers[i++].value=
+                               (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+                                    CPIA2_VC_VC_672_CLOCKS_SCALING |
+                                    CPIA2_VC_VC_CLOCKS_LOGDIV2);
+                       DBG("VC_Clocks (0xc4) should be B\n");
+               }
+               else {
+                       cmd.buffer.registers[i++].value=
+                               (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+                                    CPIA2_VC_VC_CLOCKS_LOGDIV2);
+               }
+       } else {
+               if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+                       cmd.buffer.registers[i++].value =
+                          (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
+                                CPIA2_VC_VC_CLOCKS_LOGDIV0);
+               }
+               else {
+                       cmd.buffer.registers[i++].value =
+                          (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
+                                CPIA2_VC_VC_676_CLOCKS_SCALING |
+                                CPIA2_VC_VC_CLOCKS_LOGDIV0);
+               }
+       }
+       DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value);
+
+       /* Input reqWidth from VC */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value =
+                   (u8) (STV_IMAGE_QCIF_COLS / 4);
+       else
+               cmd.buffer.registers[i++].value =
+                   (u8) (STV_IMAGE_CIF_COLS / 4);
+
+       /* Timings */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 0;
+       else
+               cmd.buffer.registers[i++].value = (u8) 1;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 208;
+       else
+               cmd.buffer.registers[i++].value = (u8) 160;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 0;
+       else
+               cmd.buffer.registers[i++].value = (u8) 1;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 160;
+       else
+               cmd.buffer.registers[i++].value = (u8) 64;
+
+       /* Output Image Size */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+       cmd.buffer.registers[i++].value = cam->params.roi.width / 4;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+       cmd.buffer.registers[i++].value = cam->params.roi.height / 4;
+
+       /* Cropping */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+       else
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+       else
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+
+       /* Scaling registers (defaults) */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+       cmd.buffer.registers[i++].value = (u8) 0;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+       cmd.buffer.registers[i++].value = (u8) 0;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+       cmd.buffer.registers[i++].value = (u8) 31;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+       cmd.buffer.registers[i++].value = (u8) 31;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+       cmd.buffer.registers[i++].value = (u8) 0;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+       cmd.buffer.registers[i++].value = (u8) 0;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+       cmd.buffer.registers[i++].value = (u8) 0x81;    /* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+       cmd.buffer.registers[i++].value = (u8) 0x81;    /* = 8/1 = 8 (HIBYTE/LOBYTE) */
+
+       cmd.reg_count = i;
+
+       cpia2_send_command(cam, &cmd);
+
+       return i;
+}
+
+
+/******************************************************************************
+ *
+ *  config_sensor_500(cam)
+ *
+ *****************************************************************************/
+static int config_sensor_500(struct camera_data *cam,
+                            int req_width, int req_height)
+{
+       struct cpia2_command cmd;
+       int i = 0;
+       int image_size = VIDEOSIZE_CIF;
+       int image_type = VIDEOSIZE_VGA;
+       int width = req_width;
+       int height = req_height;
+       unsigned int device = cam->params.pnp_id.device_type;
+
+       image_size = cpia2_match_video_size(width, height);
+
+       if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS)
+               image_type = VIDEOSIZE_VGA;
+       else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS)
+               image_type = VIDEOSIZE_CIF;
+       else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS)
+               image_type = VIDEOSIZE_QVGA;
+       else
+               image_type = VIDEOSIZE_QCIF;
+
+       if (image_size >= 0) {
+               set_vw_size(cam, image_size);
+               width = cam->params.roi.width;
+               height = cam->params.roi.height;
+       } else {
+               ERR("ConfigSensor500 failed\n");
+               return -EINVAL;
+       }
+
+       DBG("image_size = %d, width = %d, height = %d, type = %d\n",
+           image_size, width, height, image_type);
+
+       cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
+       cmd.direction = TRANSFER_WRITE;
+       i = 0;
+
+       /* VC Format */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
+       cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING;
+       i++;
+
+       /* VC Clocks */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
+       if (device == DEVICE_STV_672) {
+               if (image_type == VIDEOSIZE_VGA)
+                       cmd.buffer.registers[i].value =
+                               (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1;
+               else
+                       cmd.buffer.registers[i].value =
+                               (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING |
+                                    CPIA2_VC_VC_CLOCKS_LOGDIV3);
+       } else {
+               if (image_type == VIDEOSIZE_VGA)
+                       cmd.buffer.registers[i].value =
+                               (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0;
+               else
+                       cmd.buffer.registers[i].value =
+                               (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING |
+                                    CPIA2_VC_VC_CLOCKS_LOGDIV2);
+       }
+       i++;
+
+       DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value);
+
+       /* Input width from VP */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
+       if (image_type == VIDEOSIZE_VGA)
+               cmd.buffer.registers[i].value =
+                   (u8) (STV_IMAGE_VGA_COLS / 4);
+       else
+               cmd.buffer.registers[i].value =
+                   (u8) (STV_IMAGE_QVGA_COLS / 4);
+       i++;
+       DBG("Input width = %d\n", cmd.buffer.registers[i-1].value);
+
+       /* Timings */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
+       if (image_type == VIDEOSIZE_VGA)
+               cmd.buffer.registers[i++].value = (u8) 2;
+       else
+               cmd.buffer.registers[i++].value = (u8) 1;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
+       if (image_type == VIDEOSIZE_VGA)
+               cmd.buffer.registers[i++].value = (u8) 250;
+       else if (image_type == VIDEOSIZE_QVGA)
+               cmd.buffer.registers[i++].value = (u8) 125;
+       else
+               cmd.buffer.registers[i++].value = (u8) 160;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
+       if (image_type == VIDEOSIZE_VGA)
+               cmd.buffer.registers[i++].value = (u8) 2;
+       else
+               cmd.buffer.registers[i++].value = (u8) 1;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
+       if (image_type == VIDEOSIZE_VGA)
+               cmd.buffer.registers[i++].value = (u8) 12;
+       else if (image_type == VIDEOSIZE_QVGA)
+               cmd.buffer.registers[i++].value = (u8) 64;
+       else
+               cmd.buffer.registers[i++].value = (u8) 6;
+
+       /* Output Image Size */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS  / 4;
+       else
+               cmd.buffer.registers[i++].value = width / 4;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
+       if (image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS  / 4;
+       else
+               cmd.buffer.registers[i++].value = height / 4;
+
+       /* Cropping */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
+       if (image_type == VIDEOSIZE_VGA)
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2);
+       else if (image_type == VIDEOSIZE_QVGA)
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2);
+       else if (image_type == VIDEOSIZE_CIF)
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
+       else /*if (image_type == VIDEOSIZE_QCIF)*/
+               cmd.buffer.registers[i++].value =
+                       (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
+       if (image_type == VIDEOSIZE_VGA)
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2);
+       else if (image_type == VIDEOSIZE_QVGA)
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2);
+       else if (image_type == VIDEOSIZE_CIF)
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
+       else /*if (image_type == VIDEOSIZE_QCIF)*/
+               cmd.buffer.registers[i++].value =
+                   (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
+
+       /* Scaling registers (defaults) */
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
+       if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 36;
+       else
+               cmd.buffer.registers[i++].value = (u8) 0;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
+       if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 32;
+       else
+               cmd.buffer.registers[i++].value = (u8) 0;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
+       if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 26;
+       else
+               cmd.buffer.registers[i++].value = (u8) 31;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
+       if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 21;
+       else
+               cmd.buffer.registers[i++].value = (u8) 31;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
+       cmd.buffer.registers[i++].value = (u8) 0;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
+       cmd.buffer.registers[i++].value = (u8) 0;
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
+       if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 0x2B;    /* 2/11 */
+       else
+               cmd.buffer.registers[i++].value = (u8) 0x81;    /* 8/1 */
+
+       cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
+       if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
+               cmd.buffer.registers[i++].value = (u8) 0x13;    /* 1/3 */
+       else
+               cmd.buffer.registers[i++].value = (u8) 0x81;    /* 8/1 */
+
+       cmd.reg_count = i;
+
+       cpia2_send_command(cam, &cmd);
+
+       return i;
+}
+
+
+/******************************************************************************
+ *
+ *  setallproperties
+ *
+ *  This sets all user changeable properties to the values in cam->params.
+ *****************************************************************************/
+int set_all_properties(struct camera_data *cam)
+{
+       /**
+        * Don't set target_kb here, it will be set later.
+        * framerate and user_mode were already set (set_default_user_mode).
+        **/
+
+       cpia2_set_color_params(cam);
+
+       cpia2_usb_change_streaming_alternate(cam,
+                                         cam->params.camera_state.stream_mode);
+
+       cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+                        cam->params.vp_params.user_effects);
+
+       cpia2_set_flicker_mode(cam,
+                              cam->params.flicker_control.flicker_mode_req);
+
+       cpia2_do_command(cam,
+                        CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+                        TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
+       cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
+                        cam->params.vp_params.gpio_data);
+
+       wake_system(cam);
+
+       set_lowlight_boost(cam);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_save_camera_state
+ *
+ *****************************************************************************/
+void cpia2_save_camera_state(struct camera_data *cam)
+{
+       get_color_params(cam);
+       cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+       cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
+                        0);
+       cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0);
+       /* Don't get framerate or target_kb. Trust the values we already have */
+}
+
+/******************************************************************************
+ *
+ *  get_color_params
+ *
+ *****************************************************************************/
+void get_color_params(struct camera_data *cam)
+{
+       cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0);
+       cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0);
+       cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_color_params
+ *
+ *****************************************************************************/
+void cpia2_set_color_params(struct camera_data *cam)
+{
+       DBG("Setting color params\n");
+       cpia2_set_brightness(cam, cam->params.color_params.brightness);
+       cpia2_set_contrast(cam, cam->params.color_params.contrast);
+       cpia2_set_saturation(cam, cam->params.color_params.saturation);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_flicker_mode
+ *
+ *****************************************************************************/
+int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
+{
+       unsigned char cam_reg;
+       int err = 0;
+
+       if(cam->params.pnp_id.device_type != DEVICE_STV_672)
+               return -EINVAL;
+
+       /* Set the appropriate bits in FLICKER_MODES, preserving the rest */
+       if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
+                                  TRANSFER_READ, 0)))
+               return err;
+       cam_reg = cam->params.flicker_control.cam_register;
+
+       switch(mode) {
+       case NEVER_FLICKER:
+               cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+               cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+               break;
+       case FLICKER_60:
+               cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+               cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
+               break;
+       case FLICKER_50:
+               cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
+               cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES,
+                                  TRANSFER_WRITE, cam_reg)))
+               return err;
+
+       /* Set the appropriate bits in EXP_MODES, preserving the rest */
+       if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES,
+                                  TRANSFER_READ, 0)))
+               return err;
+       cam_reg = cam->params.vp_params.exposure_modes;
+
+       if (mode == NEVER_FLICKER) {
+               cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+       } else {
+               cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
+       }
+
+       if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES,
+                                  TRANSFER_WRITE, cam_reg)))
+               return err;
+
+       if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4,
+                                  TRANSFER_WRITE, 1)))
+               return err;
+
+       switch(mode) {
+       case NEVER_FLICKER:
+               cam->params.flicker_control.flicker_mode_req = mode;
+               break;
+       case FLICKER_60:
+               cam->params.flicker_control.flicker_mode_req = mode;
+               cam->params.flicker_control.mains_frequency = 60;
+               break;
+       case FLICKER_50:
+               cam->params.flicker_control.flicker_mode_req = mode;
+               cam->params.flicker_control.mains_frequency = 50;
+               break;
+       default:
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_property_flip
+ *
+ *****************************************************************************/
+void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
+{
+       unsigned char cam_reg;
+
+       cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+       cam_reg = cam->params.vp_params.user_effects;
+
+       if (prop_val)
+       {
+               cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP;
+       }
+       else
+       {
+               cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
+       }
+       cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+                        cam_reg);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_property_mirror
+ *
+ *****************************************************************************/
+void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
+{
+       unsigned char cam_reg;
+
+       cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
+       cam_reg = cam->params.vp_params.user_effects;
+
+       if (prop_val)
+       {
+               cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR;
+       }
+       else
+       {
+               cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
+       }
+       cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+                        cam_reg);
+}
+
+/******************************************************************************
+ *
+ *  set_target_kb
+ *
+ *  The new Target KB is set in cam->params.vc_params.target_kb and
+ *  activates on reset.
+ *****************************************************************************/
+
+int cpia2_set_target_kb(struct camera_data *cam, unsigned char value)
+{
+       DBG("Requested target_kb = %d\n", value);
+       if (value != cam->params.vc_params.target_kb) {
+
+               cpia2_usb_stream_pause(cam);
+
+               /* reset camera for new target_kb */
+               cam->params.vc_params.target_kb = value;
+               cpia2_reset_camera(cam);
+
+               cpia2_usb_stream_resume(cam);
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_gpio
+ *
+ *****************************************************************************/
+int cpia2_set_gpio(struct camera_data *cam, unsigned char setting)
+{
+       int ret;
+
+       /* Set the microport direction (register 0x90, should be defined
+        * already) to 1 (user output), and set the microport data (0x91) to
+        * the value in the ioctl argument.
+        */
+
+       ret = cpia2_do_command(cam,
+                              CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+                              CPIA2_VC_MP_DIR_OUTPUT,
+                              255);
+       if (ret < 0)
+               return ret;
+       cam->params.vp_params.gpio_direction = 255;
+
+       ret = cpia2_do_command(cam,
+                              CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+                              CPIA2_VC_MP_DIR_OUTPUT,
+                              setting);
+       if (ret < 0)
+               return ret;
+       cam->params.vp_params.gpio_data = setting;
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_fps
+ *
+ *****************************************************************************/
+int cpia2_set_fps(struct camera_data *cam, int framerate)
+{
+       int retval;
+
+       switch(framerate) {
+               case CPIA2_VP_FRAMERATE_30:
+               case CPIA2_VP_FRAMERATE_25:
+                       if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+                          cam->params.version.sensor_flags ==
+                                                   CPIA2_VP_SENSOR_FLAGS_500) {
+                               return -EINVAL;
+                       }
+                       /* Fall through */
+               case CPIA2_VP_FRAMERATE_15:
+               case CPIA2_VP_FRAMERATE_12_5:
+               case CPIA2_VP_FRAMERATE_7_5:
+               case CPIA2_VP_FRAMERATE_6_25:
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+           framerate == CPIA2_VP_FRAMERATE_15)
+               framerate = 0; /* Work around bug in VP4 */
+
+       retval = cpia2_do_command(cam,
+                                CPIA2_CMD_FRAMERATE_REQ,
+                                TRANSFER_WRITE,
+                                framerate);
+
+       if(retval == 0)
+               cam->params.vp_params.frame_rate = framerate;
+
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_brightness
+ *
+ *****************************************************************************/
+void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
+{
+       /***
+        * Don't let the register be set to zero - bug in VP4 - flash of full
+        * brightness
+        ***/
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
+               value++;
+       DBG("Setting brightness to %d (0x%0x)\n", value, value);
+       cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_contrast
+ *
+ *****************************************************************************/
+void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
+{
+       DBG("Setting contrast to %d (0x%0x)\n", value, value);
+       cam->params.color_params.contrast = value;
+       cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_saturation
+ *
+ *****************************************************************************/
+void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
+{
+       DBG("Setting saturation to %d (0x%0x)\n", value, value);
+       cam->params.color_params.saturation = value;
+       cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
+}
+
+/******************************************************************************
+ *
+ *  wake_system
+ *
+ *****************************************************************************/
+void wake_system(struct camera_data *cam)
+{
+       cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
+}
+
+/******************************************************************************
+ *
+ *  set_lowlight_boost
+ *
+ *  Valid for STV500 sensor only
+ *****************************************************************************/
+void set_lowlight_boost(struct camera_data *cam)
+{
+       struct cpia2_command cmd;
+
+       if (cam->params.pnp_id.device_type != DEVICE_STV_672 ||
+           cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500)
+               return;
+
+       cmd.direction = TRANSFER_WRITE;
+       cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+       cmd.reg_count = 3;
+       cmd.start = CPIA2_VP_RAM_ADDR_H;
+
+       cmd.buffer.block_data[0] = 0;   /* High byte of address to write to */
+       cmd.buffer.block_data[1] = 0x59;        /* Low byte of address to write to */
+       cmd.buffer.block_data[2] = 0;   /* High byte of data to write */
+
+       cpia2_send_command(cam, &cmd);
+
+       if (cam->params.vp_params.lowlight_boost) {
+               cmd.buffer.block_data[0] = 0x02;        /* Low byte data to write */
+       } else {
+               cmd.buffer.block_data[0] = 0x06;
+       }
+       cmd.start = CPIA2_VP_RAM_DATA;
+       cmd.reg_count = 1;
+       cpia2_send_command(cam, &cmd);
+
+       /* Rehash the VP4 values */
+       cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_set_format
+ *
+ *  Assumes that new size is already set in param struct.
+ *****************************************************************************/
+void cpia2_set_format(struct camera_data *cam)
+{
+       cam->flush = true;
+
+       cpia2_usb_stream_pause(cam);
+
+       /* reset camera to new size */
+       cpia2_set_low_power(cam);
+       cpia2_reset_camera(cam);
+       cam->flush = false;
+
+       cpia2_dbg_dump_registers(cam);
+
+       cpia2_usb_stream_resume(cam);
+}
+
+/******************************************************************************
+ *
+ * cpia2_dbg_dump_registers
+ *
+ *****************************************************************************/
+void cpia2_dbg_dump_registers(struct camera_data *cam)
+{
+#ifdef _CPIA2_DEBUG_
+       struct cpia2_command cmd;
+
+       if (!(debugs_on & DEBUG_DUMP_REGS))
+               return;
+
+       cmd.direction = TRANSFER_READ;
+
+       /* Start with bank 0 (SYSTEM) */
+       cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
+       cmd.reg_count = 3;
+       cmd.start = 0;
+       cpia2_send_command(cam, &cmd);
+       printk(KERN_DEBUG "System Device Hi      = 0x%X\n",
+              cmd.buffer.block_data[0]);
+       printk(KERN_DEBUG "System Device Lo      = 0x%X\n",
+              cmd.buffer.block_data[1]);
+       printk(KERN_DEBUG "System_system control = 0x%X\n",
+              cmd.buffer.block_data[2]);
+
+       /* Bank 1 (VC) */
+       cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+       cmd.reg_count = 4;
+       cmd.start = 0x80;
+       cpia2_send_command(cam, &cmd);
+       printk(KERN_DEBUG "ASIC_ID       = 0x%X\n",
+              cmd.buffer.block_data[0]);
+       printk(KERN_DEBUG "ASIC_REV      = 0x%X\n",
+              cmd.buffer.block_data[1]);
+       printk(KERN_DEBUG "PW_CONTRL     = 0x%X\n",
+              cmd.buffer.block_data[2]);
+       printk(KERN_DEBUG "WAKEUP        = 0x%X\n",
+              cmd.buffer.block_data[3]);
+
+       cmd.start = 0xA0;       /* ST_CTRL */
+       cmd.reg_count = 1;
+       cpia2_send_command(cam, &cmd);
+       printk(KERN_DEBUG "Stream ctrl   = 0x%X\n",
+              cmd.buffer.block_data[0]);
+
+       cmd.start = 0xA4;       /* Stream status */
+       cpia2_send_command(cam, &cmd);
+       printk(KERN_DEBUG "Stream status = 0x%X\n",
+              cmd.buffer.block_data[0]);
+
+       cmd.start = 0xA8;       /* USB status */
+       cmd.reg_count = 3;
+       cpia2_send_command(cam, &cmd);
+       printk(KERN_DEBUG "USB_CTRL      = 0x%X\n",
+              cmd.buffer.block_data[0]);
+       printk(KERN_DEBUG "USB_STRM      = 0x%X\n",
+              cmd.buffer.block_data[1]);
+       printk(KERN_DEBUG "USB_STATUS    = 0x%X\n",
+              cmd.buffer.block_data[2]);
+
+       cmd.start = 0xAF;       /* USB settings */
+       cmd.reg_count = 1;
+       cpia2_send_command(cam, &cmd);
+       printk(KERN_DEBUG "USB settings  = 0x%X\n",
+              cmd.buffer.block_data[0]);
+
+       cmd.start = 0xC0;       /* VC stuff */
+       cmd.reg_count = 26;
+       cpia2_send_command(cam, &cmd);
+       printk(KERN_DEBUG "VC Control    = 0x%0X\n",
+              cmd.buffer.block_data[0]);
+       printk(KERN_DEBUG "VC Format     = 0x%0X\n",
+              cmd.buffer.block_data[3]);
+       printk(KERN_DEBUG "VC Clocks     = 0x%0X\n",
+              cmd.buffer.block_data[4]);
+       printk(KERN_DEBUG "VC IHSize     = 0x%0X\n",
+              cmd.buffer.block_data[5]);
+       printk(KERN_DEBUG "VC Xlim Hi    = 0x%0X\n",
+              cmd.buffer.block_data[6]);
+       printk(KERN_DEBUG "VC XLim Lo    = 0x%0X\n",
+              cmd.buffer.block_data[7]);
+       printk(KERN_DEBUG "VC YLim Hi    = 0x%0X\n",
+              cmd.buffer.block_data[8]);
+       printk(KERN_DEBUG "VC YLim Lo    = 0x%0X\n",
+              cmd.buffer.block_data[9]);
+       printk(KERN_DEBUG "VC OHSize     = 0x%0X\n",
+              cmd.buffer.block_data[10]);
+       printk(KERN_DEBUG "VC OVSize     = 0x%0X\n",
+              cmd.buffer.block_data[11]);
+       printk(KERN_DEBUG "VC HCrop      = 0x%0X\n",
+              cmd.buffer.block_data[12]);
+       printk(KERN_DEBUG "VC VCrop      = 0x%0X\n",
+              cmd.buffer.block_data[13]);
+       printk(KERN_DEBUG "VC HPhase     = 0x%0X\n",
+              cmd.buffer.block_data[14]);
+       printk(KERN_DEBUG "VC VPhase     = 0x%0X\n",
+              cmd.buffer.block_data[15]);
+       printk(KERN_DEBUG "VC HIspan     = 0x%0X\n",
+              cmd.buffer.block_data[16]);
+       printk(KERN_DEBUG "VC VIspan     = 0x%0X\n",
+              cmd.buffer.block_data[17]);
+       printk(KERN_DEBUG "VC HiCrop     = 0x%0X\n",
+              cmd.buffer.block_data[18]);
+       printk(KERN_DEBUG "VC ViCrop     = 0x%0X\n",
+              cmd.buffer.block_data[19]);
+       printk(KERN_DEBUG "VC HiFract    = 0x%0X\n",
+              cmd.buffer.block_data[20]);
+       printk(KERN_DEBUG "VC ViFract    = 0x%0X\n",
+              cmd.buffer.block_data[21]);
+       printk(KERN_DEBUG "VC JPeg Opt   = 0x%0X\n",
+              cmd.buffer.block_data[22]);
+       printk(KERN_DEBUG "VC Creep Per  = 0x%0X\n",
+              cmd.buffer.block_data[23]);
+       printk(KERN_DEBUG "VC User Sq.   = 0x%0X\n",
+              cmd.buffer.block_data[24]);
+       printk(KERN_DEBUG "VC Target KB  = 0x%0X\n",
+              cmd.buffer.block_data[25]);
+
+       /*** VP ***/
+       cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
+       cmd.reg_count = 14;
+       cmd.start = 0;
+       cpia2_send_command(cam, &cmd);
+
+       printk(KERN_DEBUG "VP Dev Hi     = 0x%0X\n",
+              cmd.buffer.block_data[0]);
+       printk(KERN_DEBUG "VP Dev Lo     = 0x%0X\n",
+              cmd.buffer.block_data[1]);
+       printk(KERN_DEBUG "VP Sys State  = 0x%0X\n",
+              cmd.buffer.block_data[2]);
+       printk(KERN_DEBUG "VP Sys Ctrl   = 0x%0X\n",
+              cmd.buffer.block_data[3]);
+       printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n",
+              cmd.buffer.block_data[5]);
+       printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n",
+              cmd.buffer.block_data[6]);
+       printk(KERN_DEBUG "VP Dev Config = 0x%0X\n",
+              cmd.buffer.block_data[7]);
+       printk(KERN_DEBUG "VP GPIO_DIR   = 0x%0X\n",
+              cmd.buffer.block_data[8]);
+       printk(KERN_DEBUG "VP GPIO_DATA  = 0x%0X\n",
+              cmd.buffer.block_data[9]);
+       printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n",
+              cmd.buffer.block_data[10]);
+       printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n",
+              cmd.buffer.block_data[11]);
+       printk(KERN_DEBUG "VP RAM Data   = 0x%0X\n",
+              cmd.buffer.block_data[12]);
+       printk(KERN_DEBUG "Do Call       = 0x%0X\n",
+              cmd.buffer.block_data[13]);
+
+       if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
+               cmd.reg_count = 9;
+               cmd.start = 0x0E;
+               cpia2_send_command(cam, &cmd);
+               printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+                      cmd.buffer.block_data[0]);
+               printk(KERN_DEBUG "VP Patch Rev  = 0x%0X\n",
+                      cmd.buffer.block_data[1]);
+               printk(KERN_DEBUG "VP Vid Mode   = 0x%0X\n",
+                      cmd.buffer.block_data[2]);
+               printk(KERN_DEBUG "VP Framerate  = 0x%0X\n",
+                      cmd.buffer.block_data[3]);
+               printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+                      cmd.buffer.block_data[4]);
+               printk(KERN_DEBUG "VP White Bal  = 0x%0X\n",
+                      cmd.buffer.block_data[5]);
+               printk(KERN_DEBUG "VP WB thresh  = 0x%0X\n",
+                      cmd.buffer.block_data[6]);
+               printk(KERN_DEBUG "VP Exp Modes  = 0x%0X\n",
+                      cmd.buffer.block_data[7]);
+               printk(KERN_DEBUG "VP Exp Target = 0x%0X\n",
+                      cmd.buffer.block_data[8]);
+
+               cmd.reg_count = 1;
+               cmd.start = 0x1B;
+               cpia2_send_command(cam, &cmd);
+               printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n",
+                      cmd.buffer.block_data[0]);
+       } else {
+               cmd.reg_count = 8 ;
+               cmd.start = 0x0E;
+               cpia2_send_command(cam, &cmd);
+               printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
+                      cmd.buffer.block_data[0]);
+               printk(KERN_DEBUG "VP Patch Rev  = 0x%0X\n",
+                      cmd.buffer.block_data[1]);
+               printk(KERN_DEBUG "VP Vid Mode   = 0x%0X\n",
+                      cmd.buffer.block_data[5]);
+               printk(KERN_DEBUG "VP Framerate  = 0x%0X\n",
+                      cmd.buffer.block_data[6]);
+               printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
+                      cmd.buffer.block_data[7]);
+
+               cmd.reg_count = 1;
+               cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
+               cpia2_send_command(cam, &cmd);
+               printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n",
+                      cmd.buffer.block_data[0]);
+
+               cmd.reg_count = 4;
+               cmd.start = 0x3A;
+               cpia2_send_command(cam, &cmd);
+               printk(KERN_DEBUG "VP5 MY Black  = 0x%0X\n",
+                      cmd.buffer.block_data[0]);
+               printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n",
+                      cmd.buffer.block_data[1]);
+               printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n",
+                      cmd.buffer.block_data[2]);
+               printk(KERN_DEBUG "VP5 MCUV Sat  = 0x%0X\n",
+                      cmd.buffer.block_data[3]);
+       }
+#endif
+}
+
+/******************************************************************************
+ *
+ *  reset_camera_struct
+ *
+ *  Sets all values to the defaults
+ *****************************************************************************/
+void reset_camera_struct(struct camera_data *cam)
+{
+       /***
+        * The following parameter values are the defaults from the register map.
+        ***/
+       cam->params.color_params.brightness = DEFAULT_BRIGHTNESS;
+       cam->params.color_params.contrast = DEFAULT_CONTRAST;
+       cam->params.color_params.saturation = DEFAULT_SATURATION;
+       cam->params.vp_params.lowlight_boost = 0;
+
+       /* FlickerModes */
+       cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
+       cam->params.flicker_control.mains_frequency = 60;
+
+       /* jpeg params */
+       cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
+       cam->params.compression.creep_period = 2;
+       cam->params.compression.user_squeeze = 20;
+       cam->params.compression.inhibit_htables = false;
+
+       /* gpio params */
+       cam->params.vp_params.gpio_direction = 0;       /* write, the default safe mode */
+       cam->params.vp_params.gpio_data = 0;
+
+       /* Target kb params */
+       cam->params.vc_params.target_kb = DEFAULT_TARGET_KB;
+
+       /***
+        * Set Sensor FPS as fast as possible.
+        ***/
+       if(cam->params.pnp_id.device_type == DEVICE_STV_672) {
+               if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+                       cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15;
+               else
+                       cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+       } else {
+               cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
+       }
+
+       /***
+        * Set default video mode as large as possible :
+        * for vga sensor set to vga, for cif sensor set to CIF.
+        ***/
+       if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) {
+               cam->sensor_type = CPIA2_SENSOR_500;
+               cam->video_size = VIDEOSIZE_VGA;
+               cam->params.roi.width = STV_IMAGE_VGA_COLS;
+               cam->params.roi.height = STV_IMAGE_VGA_ROWS;
+       } else {
+               cam->sensor_type = CPIA2_SENSOR_410;
+               cam->video_size = VIDEOSIZE_CIF;
+               cam->params.roi.width = STV_IMAGE_CIF_COLS;
+               cam->params.roi.height = STV_IMAGE_CIF_ROWS;
+       }
+
+       /***
+        * Fill in the v4l structures.  video_cap is filled in inside the VIDIOCCAP
+        * Ioctl.  Here, just do the window and picture stucts.
+        ***/
+       cam->vp.palette = (u16) VIDEO_PALETTE_RGB24;    /* Is this right? */
+       cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
+       cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
+       cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
+
+       cam->vw.x = 0;
+       cam->vw.y = 0;
+       cam->vw.width = cam->params.roi.width;
+       cam->vw.height = cam->params.roi.height;
+       cam->vw.flags = 0;
+       cam->vw.clipcount = 0;
+
+       return;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_init_camera_struct
+ *
+ *  Initializes camera struct, does not call reset to fill in defaults.
+ *****************************************************************************/
+struct camera_data *cpia2_init_camera_struct(void)
+{
+       struct camera_data *cam;
+
+       cam = kmalloc(sizeof(*cam), GFP_KERNEL);
+
+       if (!cam) {
+               ERR("couldn't kmalloc cpia2 struct\n");
+               return NULL;
+       }
+
+       /* Default everything to 0 */
+       memset(cam, 0, sizeof(struct camera_data));
+
+       cam->present = 1;
+       init_MUTEX(&cam->busy_lock);
+       init_waitqueue_head(&cam->wq_stream);
+
+       return cam;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_init_camera
+ *
+ *  Initializes camera.
+ *****************************************************************************/
+int cpia2_init_camera(struct camera_data *cam)
+{
+       DBG("Start\n");
+
+       cam->mmapped = false;
+
+       /* Get sensor and asic types before reset. */
+       cpia2_set_high_power(cam);
+       cpia2_get_version_info(cam);
+       if (cam->params.version.asic_id != CPIA2_ASIC_672) {
+               ERR("Device IO error (asicID has incorrect value of 0x%X\n",
+                   cam->params.version.asic_id);
+               return -ENODEV;
+       }
+
+       /* Set GPIO direction and data to a safe state. */
+       cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
+                        TRANSFER_WRITE, 0);
+       cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA,
+                        TRANSFER_WRITE, 0);
+
+       /* resetting struct requires version info for sensor and asic types */
+       reset_camera_struct(cam);
+
+       cpia2_set_low_power(cam);
+
+       DBG("End\n");
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_allocate_buffers
+ *
+ *****************************************************************************/
+int cpia2_allocate_buffers(struct camera_data *cam)
+{
+       int i;
+
+       if(!cam->buffers) {
+               u32 size = cam->num_frames*sizeof(struct framebuf);
+               cam->buffers = kmalloc(size, GFP_KERNEL);
+               if(!cam->buffers) {
+                       ERR("couldn't kmalloc frame buffer structures\n");
+                       return -ENOMEM;
+               }
+       }
+
+       if(!cam->frame_buffer) {
+               cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames);
+               if (!cam->frame_buffer) {
+                       ERR("couldn't vmalloc frame buffer data area\n");
+                       kfree(cam->buffers);
+                       cam->buffers = NULL;
+                       return -ENOMEM;
+               }
+       }
+
+       for(i=0; i<cam->num_frames-1; ++i) {
+               cam->buffers[i].next = &cam->buffers[i+1];
+               cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+               cam->buffers[i].status = FRAME_EMPTY;
+               cam->buffers[i].length = 0;
+               cam->buffers[i].max_length = 0;
+               cam->buffers[i].num = i;
+       }
+       cam->buffers[i].next = cam->buffers;
+       cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
+       cam->buffers[i].status = FRAME_EMPTY;
+       cam->buffers[i].length = 0;
+       cam->buffers[i].max_length = 0;
+       cam->buffers[i].num = i;
+       cam->curbuff = cam->buffers;
+       cam->workbuff = cam->curbuff->next;
+       DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff,
+           cam->workbuff);
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_free_buffers
+ *
+ *****************************************************************************/
+void cpia2_free_buffers(struct camera_data *cam)
+{
+       if(cam->buffers) {
+               kfree(cam->buffers);
+               cam->buffers = NULL;
+       }
+       if(cam->frame_buffer) {
+               rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames);
+               cam->frame_buffer = NULL;
+       }
+}
+
+/******************************************************************************
+ *
+ *  cpia2_read
+ *
+ *****************************************************************************/
+long cpia2_read(struct camera_data *cam,
+               char __user *buf, unsigned long count, int noblock)
+{
+       struct framebuf *frame;
+       if (!count) {
+               return 0;
+       }
+
+       if (!buf) {
+               ERR("%s: buffer NULL\n",__FUNCTION__);
+               return -EINVAL;
+       }
+
+       if (!cam) {
+               ERR("%s: Internal error, camera_data NULL!\n",__FUNCTION__);
+               return -EINVAL;
+       }
+
+       /* make this _really_ smp and multithread-safe */
+       if (down_interruptible(&cam->busy_lock))
+               return -ERESTARTSYS;
+
+       if (!cam->present) {
+               LOG("%s: camera removed\n",__FUNCTION__);
+               up(&cam->busy_lock);
+               return 0;       /* EOF */
+       }
+
+       if(!cam->streaming) {
+               /* Start streaming */
+               cpia2_usb_stream_start(cam,
+                                      cam->params.camera_state.stream_mode);
+       }
+
+       /* Copy cam->curbuff in case it changes while we're processing */
+       frame = cam->curbuff;
+       if (noblock && frame->status != FRAME_READY) {
+               up(&cam->busy_lock);
+               return -EAGAIN;
+       }
+
+       if(frame->status != FRAME_READY) {
+               up(&cam->busy_lock);
+               wait_event_interruptible(cam->wq_stream,
+                              !cam->present ||
+                              (frame = cam->curbuff)->status == FRAME_READY);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+               /* make this _really_ smp and multithread-safe */
+               if (down_interruptible(&cam->busy_lock)) {
+                       return -ERESTARTSYS;
+               }
+               if(!cam->present) {
+                       up(&cam->busy_lock);
+                       return 0;
+               }
+       }
+
+       /* copy data to user space */
+       if (frame->length > count) {
+               up(&cam->busy_lock);
+               return -EFAULT;
+       }
+       if (copy_to_user(buf, frame->data, frame->length)) {
+               up(&cam->busy_lock);
+               return -EFAULT;
+       }
+
+       count = frame->length;
+
+       frame->status = FRAME_EMPTY;
+
+       up(&cam->busy_lock);
+       return count;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_poll
+ *
+ *****************************************************************************/
+unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
+                       poll_table *wait)
+{
+       unsigned int status=0;
+
+       if(!cam) {
+               ERR("%s: Internal error, camera_data not found!\n",__FUNCTION__);
+               return POLLERR;
+       }
+
+       down(&cam->busy_lock);
+
+       if(!cam->present) {
+               up(&cam->busy_lock);
+               return POLLHUP;
+       }
+
+       if(!cam->streaming) {
+               /* Start streaming */
+               cpia2_usb_stream_start(cam,
+                                      cam->params.camera_state.stream_mode);
+       }
+
+       up(&cam->busy_lock);
+       poll_wait(filp, &cam->wq_stream, wait);
+       down(&cam->busy_lock);
+
+       if(!cam->present)
+               status = POLLHUP;
+       else if(cam->curbuff->status == FRAME_READY)
+               status = POLLIN | POLLRDNORM;
+
+       up(&cam->busy_lock);
+       return status;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_remap_buffer
+ *
+ *****************************************************************************/
+int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
+{
+       const char *adr = (const char *)vma->vm_start;
+       unsigned long size = vma->vm_end-vma->vm_start;
+       unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT;
+       unsigned long start = (unsigned long) adr;
+       unsigned long page, pos;
+
+       if (!cam)
+               return -ENODEV;
+
+       DBG("mmap offset:%ld size:%ld\n", start_offset, size);
+
+       /* make this _really_ smp-safe */
+       if (down_interruptible(&cam->busy_lock))
+               return -ERESTARTSYS;
+
+       if (!cam->present) {
+               up(&cam->busy_lock);
+               return -ENODEV;
+       }
+
+       if (size > cam->frame_size*cam->num_frames  ||
+           (start_offset % cam->frame_size) != 0 ||
+           (start_offset+size > cam->frame_size*cam->num_frames)) {
+               up(&cam->busy_lock);
+               return -EINVAL;
+       }
+
+       pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
+       while (size > 0) {
+               page = kvirt_to_pa(pos);
+               if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) {
+                       up(&cam->busy_lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       cam->mmapped = true;
+       up(&cam->busy_lock);
+       return 0;
+}
+
diff --git a/drivers/media/video/cpia2/cpia2_registers.h b/drivers/media/video/cpia2/cpia2_registers.h
new file mode 100644 (file)
index 0000000..3bbec51
--- /dev/null
@@ -0,0 +1,476 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2registers.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Description:
+ *     Definitions for the CPia2 register set
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef CPIA2_REGISTER_HEADER
+#define CPIA2_REGISTER_HEADER
+
+/***
+ * System register set (Bank 0)
+ ***/
+#define CPIA2_SYSTEM_DEVICE_HI                     0x00
+#define CPIA2_SYSTEM_DEVICE_LO                     0x01
+
+#define CPIA2_SYSTEM_SYSTEM_CONTROL                0x02
+#define CPIA2_SYSTEM_CONTROL_LOW_POWER       0x00
+#define CPIA2_SYSTEM_CONTROL_HIGH_POWER      0x01
+#define CPIA2_SYSTEM_CONTROL_SUSPEND         0x02
+#define CPIA2_SYSTEM_CONTROL_V2W_ERR         0x10
+#define CPIA2_SYSTEM_CONTROL_RB_ERR          0x10
+#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR       0x80
+
+#define CPIA2_SYSTEM_INT_PACKET_CTRL                0x04
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF   0x02
+#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1  0x04
+
+#define CPIA2_SYSTEM_CACHE_CTRL                     0x05
+#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET      0x01
+#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH      0x02
+
+#define CPIA2_SYSTEM_SERIAL_CTRL                    0x06
+#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD        0x00
+#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD       0x01
+#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD        0x02
+#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD       0x03
+#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD    0x04
+#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD   0x05
+
+#define CPIA2_SYSTEM_SERIAL_DATA                     0x07
+
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR                  0x08
+
+/***
+ * I2C addresses for various devices in CPiA2
+ ***/
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR           0x20
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP               0x88
+#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP           0x8A
+
+#define CPIA2_SYSTEM_SPARE_REG1                      0x09
+#define CPIA2_SYSTEM_SPARE_REG2                      0x0A
+#define CPIA2_SYSTEM_SPARE_REG3                      0x0B
+
+#define CPIA2_SYSTEM_MC_PORT_0                       0x0C
+#define CPIA2_SYSTEM_MC_PORT_1                       0x0D
+#define CPIA2_SYSTEM_MC_PORT_2                       0x0E
+#define CPIA2_SYSTEM_MC_PORT_3                       0x0F
+
+#define CPIA2_SYSTEM_STATUS_PKT                      0x20
+#define CPIA2_SYSTEM_STATUS_PKT_END                  0x27
+
+#define CPIA2_SYSTEM_DESCRIP_VID_HI                  0x30
+#define CPIA2_SYSTEM_DESCRIP_VID_LO                  0x31
+#define CPIA2_SYSTEM_DESCRIP_PID_HI                  0x32
+#define CPIA2_SYSTEM_DESCRIP_PID_LO                  0x33
+
+#define CPIA2_SYSTEM_FW_VERSION_HI                   0x34
+#define CPIA2_SYSTEM_FW_VERSION_LO                   0x35
+
+#define CPIA2_SYSTEM_CACHE_START_INDEX               0x80
+#define CPIA2_SYSTEM_CACHE_MAX_WRITES                0x10
+
+/***
+ * VC register set (Bank 1)
+ ***/
+#define CPIA2_VC_ASIC_ID                 0x80
+
+#define CPIA2_VC_ASIC_REV                0x81
+
+#define CPIA2_VC_PW_CTRL                 0x82
+#define CPIA2_VC_PW_CTRL_COLDSTART      0x01
+#define CPIA2_VC_PW_CTRL_CP_CLK_EN      0x02
+#define CPIA2_VC_PW_CTRL_VP_RESET_N     0x04
+#define CPIA2_VC_PW_CTRL_VC_CLK_EN      0x08
+#define CPIA2_VC_PW_CTRL_VC_RESET_N     0x10
+#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND   0x20
+#define CPIA2_VC_PW_CTRL_UDC_SUSPEND    0x40
+#define CPIA2_VC_PW_CTRL_PWR_DOWN       0x80
+
+#define CPIA2_VC_WAKEUP                   0x83
+#define CPIA2_VC_WAKEUP_SW_ENABLE       0x01
+#define CPIA2_VC_WAKEUP_XX_ENABLE       0x02
+#define CPIA2_VC_WAKEUP_SW_ATWAKEUP     0x04
+#define CPIA2_VC_WAKEUP_XX_ATWAKEUP     0x08
+
+#define CPIA2_VC_CLOCK_CTRL               0x84
+#define CPIA2_VC_CLOCK_CTRL_TESTUP72    0x01
+
+#define CPIA2_VC_INT_ENABLE                0x88
+#define CPIA2_VC_INT_ENABLE_XX_IE       0x01
+#define CPIA2_VC_INT_ENABLE_SW_IE       0x02
+#define CPIA2_VC_INT_ENABLE_VC_IE       0x04
+#define CPIA2_VC_INT_ENABLE_USBDATA_IE  0x08
+#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10
+#define CPIA2_VC_INT_ENABLE_USBCFG_IE   0x20
+
+#define CPIA2_VC_INT_FLAG                  0x89
+#define CPIA2_VC_INT_ENABLE_XX_FLAG       0x01
+#define CPIA2_VC_INT_ENABLE_SW_FLAG       0x02
+#define CPIA2_VC_INT_ENABLE_VC_FLAG       0x04
+#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG  0x08
+#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10
+#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG   0x20
+#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80
+
+#define CPIA2_VC_INT_STATE                 0x8A
+#define CPIA2_VC_INT_STATE_XX_STATE     0x01
+#define CPIA2_VC_INT_STATE_SW_STATE     0x02
+
+#define CPIA2_VC_MP_DIR                    0x90
+#define CPIA2_VC_MP_DIR_INPUT           0x00
+#define CPIA2_VC_MP_DIR_OUTPUT          0x01
+
+#define CPIA2_VC_MP_DATA                   0x91
+
+#define CPIA2_VC_DP_CTRL                   0x98
+#define CPIA2_VC_DP_CTRL_MODE_0         0x00
+#define CPIA2_VC_DP_CTRL_MODE_A         0x01
+#define CPIA2_VC_DP_CTRL_MODE_B         0x02
+#define CPIA2_VC_DP_CTRL_MODE_C         0x03
+#define CPIA2_VC_DP_CTRL_FAKE_FST       0x04
+
+#define CPIA2_VC_AD_CTRL                   0x99
+#define CPIA2_VC_AD_CTRL_SRC_0          0x00
+#define CPIA2_VC_AD_CTRL_SRC_DIGI_A     0x01
+#define CPIA2_VC_AD_CTRL_SRC_REG        0x02
+#define CPIA2_VC_AD_CTRL_DST_USB        0x00
+#define CPIA2_VC_AD_CTRL_DST_REG        0x04
+
+#define CPIA2_VC_AD_TEST_IN                0x9B
+
+#define CPIA2_VC_AD_TEST_OUT               0x9C
+
+#define CPIA2_VC_AD_STATUS                 0x9D
+#define CPIA2_VC_AD_STATUS_EMPTY        0x01
+#define CPIA2_VC_AD_STATUS_FULL         0x02
+
+#define CPIA2_VC_DP_DATA                   0x9E
+
+#define CPIA2_VC_ST_CTRL                   0xA0
+#define CPIA2_VC_ST_CTRL_SRC_VC         0x00
+#define CPIA2_VC_ST_CTRL_SRC_DP         0x01
+#define CPIA2_VC_ST_CTRL_SRC_REG        0x02
+
+#define CPIA2_VC_ST_CTRL_RAW_SELECT     0x04
+
+#define CPIA2_VC_ST_CTRL_DST_USB        0x00
+#define CPIA2_VC_ST_CTRL_DST_DP         0x08
+#define CPIA2_VC_ST_CTRL_DST_REG        0x10
+
+#define CPIA2_VC_ST_CTRL_FIFO_ENABLE    0x20
+#define CPIA2_VC_ST_CTRL_EOF_DETECT     0x40
+
+#define CPIA2_VC_ST_TEST                   0xA1
+#define CPIA2_VC_ST_TEST_MODE_MANUAL    0x00
+#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02
+
+#define CPIA2_VC_ST_TEST_AUTO_FILL      0x08
+
+#define CPIA2_VC_ST_TEST_REPEAT_FIFO    0x10
+
+#define CPIA2_VC_ST_TEST_IN                0xA2
+
+#define CPIA2_VC_ST_TEST_OUT               0xA3
+
+#define CPIA2_VC_ST_STATUS                 0xA4
+#define CPIA2_VC_ST_STATUS_EMPTY        0x01
+#define CPIA2_VC_ST_STATUS_FULL         0x02
+
+#define CPIA2_VC_ST_FRAME_DETECT_1         0xA5
+
+#define CPIA2_VC_ST_FRAME_DETECT_2         0xA6
+
+#define CPIA2_VC_USB_CTRL                    0xA8
+#define CPIA2_VC_USB_CTRL_CMD_STALLED      0x01
+#define CPIA2_VC_USB_CTRL_CMD_READY        0x02
+#define CPIA2_VC_USB_CTRL_CMD_STATUS       0x04
+#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR   0x08
+#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH     0x10
+#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80
+
+#define CPIA2_VC_USB_STRM                  0xA9
+#define CPIA2_VC_USB_STRM_ISO_ENABLE    0x01
+#define CPIA2_VC_USB_STRM_BLK_ENABLE    0x02
+#define CPIA2_VC_USB_STRM_INT_ENABLE    0x04
+#define CPIA2_VC_USB_STRM_AUD_ENABLE    0x08
+
+#define CPIA2_VC_USB_STATUS                   0xAA
+#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS  0x01
+#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02
+#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE    0x04
+#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE     0x08
+#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY    0x10
+#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN  0x20
+#define CPIA2_VC_USB_STATUS_CONFIG_DONE      0x40
+#define CPIA2_VC_USB_STATUS_USB_SUSPEND      0x80
+
+#define CPIA2_VC_USB_CMDW                   0xAB
+
+#define CPIA2_VC_USB_DATARW                 0xAC
+
+#define CPIA2_VC_USB_INFO                   0xAD
+
+#define CPIA2_VC_USB_CONFIG                 0xAE
+
+#define CPIA2_VC_USB_SETTINGS                  0xAF
+#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK    0x03
+#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C
+#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70
+
+#define CPIA2_VC_USB_ISOLIM                  0xB0
+
+#define CPIA2_VC_USB_ISOFAILS                0xB1
+
+#define CPIA2_VC_USB_ISOMAXPKTHI             0xB2
+
+#define CPIA2_VC_USB_ISOMAXPKTLO             0xB3
+
+#define CPIA2_VC_V2W_CTRL                    0xB8
+#define CPIA2_VC_V2W_SELECT               0x01
+
+#define CPIA2_VC_V2W_SCL                     0xB9
+
+#define CPIA2_VC_V2W_SDA                     0xBA
+
+#define CPIA2_VC_VC_CTRL                     0xC0
+#define CPIA2_VC_VC_CTRL_RUN              0x01
+#define CPIA2_VC_VC_CTRL_SINGLESHOT       0x02
+#define CPIA2_VC_VC_CTRL_IDLING           0x04
+#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10
+#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20
+#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE  0x40
+
+#define CPIA2_VC_VC_RESTART_IVAL_HI          0xC1
+
+#define CPIA2_VC_VC_RESTART_IVAL_LO          0xC2
+
+#define CPIA2_VC_VC_FORMAT                   0xC3
+#define CPIA2_VC_VC_FORMAT_UFIRST         0x01
+#define CPIA2_VC_VC_FORMAT_MONO           0x02
+#define CPIA2_VC_VC_FORMAT_DECIMATING     0x04
+#define CPIA2_VC_VC_FORMAT_SHORTLINE      0x08
+#define CPIA2_VC_VC_FORMAT_SELFTEST       0x10
+
+#define CPIA2_VC_VC_CLOCKS                         0xC4
+#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK        0x03
+#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3   0x04
+#define CPIA2_VC_VC_672_CLOCKS_SCALING        0x08
+#define CPIA2_VC_VC_CLOCKS_LOGDIV0        0x00
+#define CPIA2_VC_VC_CLOCKS_LOGDIV1        0x01
+#define CPIA2_VC_VC_CLOCKS_LOGDIV2        0x02
+#define CPIA2_VC_VC_CLOCKS_LOGDIV3        0x03
+#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3   0x08
+#define CPIA2_VC_VC_676_CLOCKS_SCALING       0x10
+
+#define CPIA2_VC_VC_IHSIZE_LO                0xC5
+
+#define CPIA2_VC_VC_XLIM_HI                  0xC6
+
+#define CPIA2_VC_VC_XLIM_LO                  0xC7
+
+#define CPIA2_VC_VC_YLIM_HI                  0xC8
+
+#define CPIA2_VC_VC_YLIM_LO                  0xC9
+
+#define CPIA2_VC_VC_OHSIZE                   0xCA
+
+#define CPIA2_VC_VC_OVSIZE                   0xCB
+
+#define CPIA2_VC_VC_HCROP                    0xCC
+
+#define CPIA2_VC_VC_VCROP                    0xCD
+
+#define CPIA2_VC_VC_HPHASE                   0xCE
+
+#define CPIA2_VC_VC_VPHASE                   0xCF
+
+#define CPIA2_VC_VC_HISPAN                   0xD0
+
+#define CPIA2_VC_VC_VISPAN                   0xD1
+
+#define CPIA2_VC_VC_HICROP                   0xD2
+
+#define CPIA2_VC_VC_VICROP                   0xD3
+
+#define CPIA2_VC_VC_HFRACT                   0xD4
+#define CPIA2_VC_VC_HFRACT_DEN_MASK       0x0F
+#define CPIA2_VC_VC_HFRACT_NUM_MASK       0xF0
+
+#define CPIA2_VC_VC_VFRACT                   0xD5
+#define CPIA2_VC_VC_VFRACT_DEN_MASK       0x0F
+#define CPIA2_VC_VC_VFRACT_NUM_MASK       0xF0
+
+#define CPIA2_VC_VC_JPEG_OPT                      0xD6
+#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE     0x01
+#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02
+#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE       0x04
+#define CPIA2_VC_VC_JPEG_OPT_DEFAULT      (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\
+                                          CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE)
+
+
+#define CPIA2_VC_VC_CREEP_PERIOD             0xD7
+#define CPIA2_VC_VC_USER_SQUEEZE             0xD8
+#define CPIA2_VC_VC_TARGET_KB                0xD9
+
+#define CPIA2_VC_VC_AUTO_SQUEEZE             0xE6
+
+
+/***
+ * VP register set (Bank 2)
+ ***/
+#define CPIA2_VP_DEVICEH                             0
+#define CPIA2_VP_DEVICEL                             1
+
+#define CPIA2_VP_SYSTEMSTATE                         0x02
+#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE             0x01
+
+#define CPIA2_VP_SYSTEMCTRL                          0x03
+#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR       0x80
+#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL        0x20
+#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE     0x10
+#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP     0x08
+#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD          0x04
+#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL            0x02
+#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL         0x01
+
+#define CPIA2_VP_SENSOR_FLAGS                        0x05
+#define CPIA2_VP_SENSOR_FLAGS_404                 0x01
+#define CPIA2_VP_SENSOR_FLAGS_407                 0x02
+#define CPIA2_VP_SENSOR_FLAGS_409                 0x04
+#define CPIA2_VP_SENSOR_FLAGS_410                 0x08
+#define CPIA2_VP_SENSOR_FLAGS_500                 0x10
+
+#define CPIA2_VP_SENSOR_REV                          0x06
+
+#define CPIA2_VP_DEVICE_CONFIG                       0x07
+#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE      0x01
+
+#define CPIA2_VP_GPIO_DIRECTION                      0x08
+#define CPIA2_VP_GPIO_READ                        0xFF
+#define CPIA2_VP_GPIO_WRITE                       0x00
+
+#define CPIA2_VP_GPIO_DATA                           0x09
+
+#define CPIA2_VP_RAM_ADDR_H                          0x0A
+#define CPIA2_VP_RAM_ADDR_L                          0x0B
+#define CPIA2_VP_RAM_DATA                            0x0C
+
+#define CPIA2_VP_PATCH_REV                           0x0F
+
+#define CPIA2_VP4_USER_MODE                           0x10
+#define CPIA2_VP5_USER_MODE                           0x13
+#define CPIA2_VP_USER_MODE_CIF                    0x01
+#define CPIA2_VP_USER_MODE_QCIFDS                 0x02
+#define CPIA2_VP_USER_MODE_QCIFPTC                0x04
+#define CPIA2_VP_USER_MODE_QVGADS                 0x08
+#define CPIA2_VP_USER_MODE_QVGAPTC                0x10
+#define CPIA2_VP_USER_MODE_VGA                    0x20
+
+#define CPIA2_VP4_FRAMERATE_REQUEST                    0x11
+#define CPIA2_VP5_FRAMERATE_REQUEST                    0x14
+#define CPIA2_VP_FRAMERATE_60                     0x80
+#define CPIA2_VP_FRAMERATE_50                     0x40
+#define CPIA2_VP_FRAMERATE_30                     0x20
+#define CPIA2_VP_FRAMERATE_25                     0x10
+#define CPIA2_VP_FRAMERATE_15                     0x08
+#define CPIA2_VP_FRAMERATE_12_5                   0x04
+#define CPIA2_VP_FRAMERATE_7_5                    0x02
+#define CPIA2_VP_FRAMERATE_6_25                   0x01
+
+#define CPIA2_VP4_USER_EFFECTS                         0x12
+#define CPIA2_VP5_USER_EFFECTS                         0x15
+#define CPIA2_VP_USER_EFFECTS_COLBARS             0x01
+#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD        0x02
+#define CPIA2_VP_USER_EFFECTS_MIRROR              0x04
+#define CPIA2_VP_USER_EFFECTS_FLIP                0x40  // VP5 only
+
+/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User
+ * Effects */
+#define CPIA2_VP_EXPOSURE_MODES                       0x15
+#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER   0x20
+#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP       0x10
+
+#define CPIA2_VP4_EXPOSURE_TARGET                     0x16    // VP4
+#define CPIA2_VP5_EXPOSURE_TARGET                    0x20    // VP5
+
+#define CPIA2_VP_FLICKER_MODES                        0x1B
+#define CPIA2_VP_FLICKER_MODES_50HZ               0x80
+#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ   0x40
+#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER      0x20
+#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB        0x10
+#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ   0x08
+#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ   0x04
+
+#define CPIA2_VP_UMISC                                0x1D
+#define CPIA2_VP_UMISC_FORCE_MONO                 0x80
+#define CPIA2_VP_UMISC_FORCE_ID_MASK              0x40
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS           0x20
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS          0x08
+#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS          0x04
+#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT      0x02
+
+#define CPIA2_VP5_ANTIFLKRSETUP                       0x22  //34
+
+#define CPIA2_VP_INTERPOLATION                        0x24
+#define CPIA2_VP_INTERPOLATION_EVEN_FIRST         0x40
+#define CPIA2_VP_INTERPOLATION_HJOG               0x20
+#define CPIA2_VP_INTERPOLATION_VJOG               0x10
+
+#define CPIA2_VP_GAMMA                                0x25
+#define CPIA2_VP_DEFAULT_GAMMA                    0x10
+
+#define CPIA2_VP_YRANGE                               0x26
+
+#define CPIA2_VP_SATURATION                           0x27
+
+#define CPIA2_VP5_MYBLACK_LEVEL                       0x3A   //58
+#define CPIA2_VP5_MCYRANGE                            0x3B   //59
+#define CPIA2_VP5_MYCEILING                           0x3C   //60
+#define CPIA2_VP5_MCUVSATURATION                      0x3D   //61
+
+
+#define CPIA2_VP_REHASH_VALUES                        0x60
+
+
+/***
+ * Common sensor registers
+ ***/
+#define CPIA2_SENSOR_DEVICE_H                         0x00
+#define CPIA2_SENSOR_DEVICE_L                         0x01
+
+#define CPIA2_SENSOR_DATA_FORMAT                      0x16
+#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR      0x08
+#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR      0x10
+
+#define CPIA2_SENSOR_CR1                              0x76
+#define CPIA2_SENSOR_CR1_STAND_BY             0x01
+#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN        0x02
+#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC      0x04
+#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR   0x08
+#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10
+#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP         0x20
+#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP        0x40
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
new file mode 100644 (file)
index 0000000..f4da029
--- /dev/null
@@ -0,0 +1,907 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_usb.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *             Alan Cox <alan@redhat.com>
+ ****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "cpia2.h"
+
+static int frame_sizes[] = {
+       0,      // USBIF_CMDONLY
+       0,      // USBIF_BULK
+       128,    // USBIF_ISO_1
+       384,    // USBIF_ISO_2
+       640,    // USBIF_ISO_3
+       768,    // USBIF_ISO_4
+       896,    // USBIF_ISO_5
+       1023,   // USBIF_ISO_6
+};
+
+#define FRAMES_PER_DESC    10
+#define FRAME_SIZE_PER_DESC   frame_sizes[cam->cur_alt]
+
+static void process_frame(struct camera_data *cam);
+static void cpia2_usb_complete(struct urb *urb, struct pt_regs *);
+static int cpia2_usb_probe(struct usb_interface *intf,
+                          const struct usb_device_id *id);
+static void cpia2_usb_disconnect(struct usb_interface *intf);
+
+static void free_sbufs(struct camera_data *cam);
+static void add_APPn(struct camera_data *cam);
+static void add_COM(struct camera_data *cam);
+static int submit_urbs(struct camera_data *cam);
+static int set_alternate(struct camera_data *cam, unsigned int alt);
+static int configure_transfer_mode(struct camera_data *cam, unsigned int alt);
+
+static struct usb_device_id cpia2_id_table[] = {
+       {USB_DEVICE(0x0553, 0x0100)},
+       {USB_DEVICE(0x0553, 0x0140)},
+       {USB_DEVICE(0x0553, 0x0151)},  /* STV0676 */
+       {}                      /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, cpia2_id_table);
+
+static struct usb_driver cpia2_driver = {
+       .name           = "cpia2",
+       .probe          = cpia2_usb_probe,
+       .disconnect     = cpia2_usb_disconnect,
+       .id_table       = cpia2_id_table
+};
+
+
+/******************************************************************************
+ *
+ *  process_frame
+ *
+ *****************************************************************************/
+static void process_frame(struct camera_data *cam)
+{
+       static int frame_count = 0;
+
+       unsigned char *inbuff = cam->workbuff->data;
+
+       DBG("Processing frame #%d, current:%d\n",
+           cam->workbuff->num, cam->curbuff->num);
+
+       if(cam->workbuff->length > cam->workbuff->max_length)
+               cam->workbuff->max_length = cam->workbuff->length;
+
+       if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) {
+               frame_count++;
+       } else {
+               cam->workbuff->status = FRAME_ERROR;
+               DBG("Start of frame not found\n");
+               return;
+       }
+
+       /***
+        * Now the output buffer should have a JPEG image in it.
+        ***/
+       if(!cam->first_image_seen) {
+               /* Always skip the first image after streaming
+                * starts. It is almost certainly corrupt. */
+               cam->first_image_seen = 1;
+               cam->workbuff->status = FRAME_EMPTY;
+               return;
+       }
+       if (cam->workbuff->length > 3) {
+               if(cam->mmapped &&
+                  cam->workbuff->length < cam->workbuff->max_length) {
+                       /* No junk in the buffers */
+                       memset(cam->workbuff->data+cam->workbuff->length,
+                              0, cam->workbuff->max_length-
+                                 cam->workbuff->length);
+               }
+               cam->workbuff->max_length = cam->workbuff->length;
+               cam->workbuff->status = FRAME_READY;
+
+               if(!cam->mmapped && cam->num_frames > 2) {
+                       /* During normal reading, the most recent
+                        * frame will be read.  If the current frame
+                        * hasn't started reading yet, it will never
+                        * be read, so mark it empty.  If the buffer is
+                        * mmapped, or we have few buffers, we need to
+                        * wait for the user to free the buffer.
+                        *
+                        * NOTE: This is not entirely foolproof with 3
+                        * buffers, but it would take an EXTREMELY
+                        * overloaded system to cause problems (possible
+                        * image data corruption).  Basically, it would
+                        * need to take more time to execute cpia2_read
+                        * than it would for the camera to send
+                        * cam->num_frames-2 frames before problems
+                        * could occur.
+                        */
+                       cam->curbuff->status = FRAME_EMPTY;
+               }
+               cam->curbuff = cam->workbuff;
+               cam->workbuff = cam->workbuff->next;
+               DBG("Changed buffers, work:%d, current:%d\n",
+                   cam->workbuff->num, cam->curbuff->num);
+               return;
+       } else {
+               DBG("Not enough data for an image.\n");
+       }
+
+       cam->workbuff->status = FRAME_ERROR;
+       return;
+}
+
+/******************************************************************************
+ *
+ *  add_APPn
+ *
+ *  Adds a user specified APPn record
+ *****************************************************************************/
+static void add_APPn(struct camera_data *cam)
+{
+       if(cam->APP_len > 0) {
+               cam->workbuff->data[cam->workbuff->length++] = 0xFF;
+               cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn;
+               cam->workbuff->data[cam->workbuff->length++] = 0;
+               cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2;
+               memcpy(cam->workbuff->data+cam->workbuff->length,
+                      cam->APP_data, cam->APP_len);
+               cam->workbuff->length += cam->APP_len;
+       }
+}
+
+/******************************************************************************
+ *
+ *  add_COM
+ *
+ *  Adds a user specified COM record
+ *****************************************************************************/
+static void add_COM(struct camera_data *cam)
+{
+       if(cam->COM_len > 0) {
+               cam->workbuff->data[cam->workbuff->length++] = 0xFF;
+               cam->workbuff->data[cam->workbuff->length++] = 0xFE;
+               cam->workbuff->data[cam->workbuff->length++] = 0;
+               cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2;
+               memcpy(cam->workbuff->data+cam->workbuff->length,
+                      cam->COM_data, cam->COM_len);
+               cam->workbuff->length += cam->COM_len;
+       }
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_complete
+ *
+ *  callback when incoming packet is received
+ *****************************************************************************/
+static void cpia2_usb_complete(struct urb *urb, struct pt_regs *regs)
+{
+       int i;
+       unsigned char *cdata;
+       static int frame_ready = false;
+       struct camera_data *cam = (struct camera_data *) urb->context;
+
+       if (urb->status!=0) {
+               if (!(urb->status == -ENOENT ||
+                     urb->status == -ECONNRESET ||
+                     urb->status == -ESHUTDOWN))
+               {
+                       DBG("urb->status = %d!\n", urb->status);
+               }
+               DBG("Stopping streaming\n");
+               return;
+       }
+
+       if (!cam->streaming || !cam->present || cam->open_count == 0) {
+               LOG("Will now stop the streaming: streaming = %d, "
+                   "present=%d, open_count=%d\n",
+                   cam->streaming, cam->present, cam->open_count);
+               return;
+       }
+
+       /***
+        * Packet collater
+        ***/
+       //DBG("Collating %d packets\n", urb->number_of_packets);
+       for (i = 0; i < urb->number_of_packets; i++) {
+               u16 checksum, iso_checksum;
+               int j;
+               int n = urb->iso_frame_desc[i].actual_length;
+               int st = urb->iso_frame_desc[i].status;
+
+               if(cam->workbuff->status == FRAME_READY) {
+                       struct framebuf *ptr;
+                       /* Try to find an available buffer */
+                       DBG("workbuff full, searching\n");
+                       for (ptr = cam->workbuff->next;
+                            ptr != cam->workbuff;
+                            ptr = ptr->next)
+                       {
+                               if (ptr->status == FRAME_EMPTY) {
+                                       ptr->status = FRAME_READING;
+                                       ptr->length = 0;
+                                       break;
+                               }
+                       }
+                       if (ptr == cam->workbuff)
+                               break; /* No READING or EMPTY buffers left */
+
+                       cam->workbuff = ptr;
+               }
+
+               if (cam->workbuff->status == FRAME_EMPTY ||
+                   cam->workbuff->status == FRAME_ERROR) {
+                       cam->workbuff->status = FRAME_READING;
+                       cam->workbuff->length = 0;
+               }
+
+               //DBG("   Packet %d length = %d, status = %d\n", i, n, st);
+               cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+               if (st) {
+                       LOG("cpia2 data error: [%d] len=%d, status = %d\n",
+                           i, n, st);
+                       if(!ALLOW_CORRUPT)
+                               cam->workbuff->status = FRAME_ERROR;
+                       continue;
+               }
+
+               if(n<=2)
+                       continue;
+
+               checksum = 0;
+               for(j=0; j<n-2; ++j)
+                       checksum += cdata[j];
+               iso_checksum = cdata[j] + cdata[j+1]*256;
+               if(checksum != iso_checksum) {
+                       LOG("checksum mismatch: [%d] len=%d, calculated = %x, checksum = %x\n",
+                           i, n, (int)checksum, (int)iso_checksum);
+                       if(!ALLOW_CORRUPT) {
+                               cam->workbuff->status = FRAME_ERROR;
+                               continue;
+                       }
+               }
+               n -= 2;
+
+               if(cam->workbuff->status != FRAME_READING) {
+                       if((0xFF == cdata[0] && 0xD8 == cdata[1]) ||
+                          (0xD8 == cdata[0] && 0xFF == cdata[1] &&
+                           0 != cdata[2])) {
+                               /* frame is skipped, but increment total
+                                * frame count anyway */
+                               cam->frame_count++;
+                       }
+                       DBG("workbuff not reading, status=%d\n",
+                           cam->workbuff->status);
+                       continue;
+               }
+
+               if (cam->frame_size < cam->workbuff->length + n) {
+                       ERR("buffer overflow! length: %d, n: %d\n",
+                           cam->workbuff->length, n);
+                       cam->workbuff->status = FRAME_ERROR;
+                       if(cam->workbuff->length > cam->workbuff->max_length)
+                               cam->workbuff->max_length =
+                                       cam->workbuff->length;
+                       continue;
+               }
+
+               if (cam->workbuff->length == 0) {
+                       int data_offset;
+                       if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) {
+                               data_offset = 1;
+                       } else if((0xFF == cdata[0]) && (0xD8 == cdata[1])
+                                 && (0xFF == cdata[2])) {
+                               data_offset = 2;
+                       } else {
+                               DBG("Ignoring packet, not beginning!\n");
+                               continue;
+                       }
+                       DBG("Start of frame pattern found\n");
+                       do_gettimeofday(&cam->workbuff->timestamp);
+                       cam->workbuff->seq = cam->frame_count++;
+                       cam->workbuff->data[0] = 0xFF;
+                       cam->workbuff->data[1] = 0xD8;
+                       cam->workbuff->length = 2;
+                       add_APPn(cam);
+                       add_COM(cam);
+                       memcpy(cam->workbuff->data+cam->workbuff->length,
+                              cdata+data_offset, n-data_offset);
+                       cam->workbuff->length += n-data_offset;
+               } else if (cam->workbuff->length > 0) {
+                       memcpy(cam->workbuff->data + cam->workbuff->length,
+                              cdata, n);
+                       cam->workbuff->length += n;
+               }
+
+               if ((cam->workbuff->length >= 3) &&
+                   (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) &&
+                   (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) &&
+                   (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) {
+                       frame_ready = true;
+                       cam->workbuff->data[cam->workbuff->length - 1] = 0;
+                       cam->workbuff->length -= 1;
+               } else if ((cam->workbuff->length >= 2) &&
+                  (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) &&
+                  (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) {
+                       frame_ready = true;
+               }
+
+               if (frame_ready) {
+                       DBG("Workbuff image size = %d\n",cam->workbuff->length);
+                       process_frame(cam);
+
+                       frame_ready = false;
+
+                       if (waitqueue_active(&cam->wq_stream))
+                               wake_up_interruptible(&cam->wq_stream);
+               }
+       }
+
+       if(cam->streaming) {
+               /* resubmit */
+               urb->dev = cam->dev;
+               if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
+                       ERR("%s: usb_submit_urb ret %d!\n", __func__, i);
+       }
+}
+
+/******************************************************************************
+ *
+ * configure_transfer_mode
+ *
+ *****************************************************************************/
+static int configure_transfer_mode(struct camera_data *cam, unsigned int alt)
+{
+       static unsigned char iso_regs[8][4] = {
+               {0x00, 0x00, 0x00, 0x00},
+               {0x00, 0x00, 0x00, 0x00},
+               {0xB9, 0x00, 0x00, 0x7E},
+               {0xB9, 0x00, 0x01, 0x7E},
+               {0xB9, 0x00, 0x02, 0x7E},
+               {0xB9, 0x00, 0x02, 0xFE},
+               {0xB9, 0x00, 0x03, 0x7E},
+               {0xB9, 0x00, 0x03, 0xFD}
+       };
+       struct cpia2_command cmd;
+       unsigned char reg;
+
+       if(!cam->present)
+               return -ENODEV;
+
+       /***
+        * Write the isoc registers according to the alternate selected
+        ***/
+       cmd.direction = TRANSFER_WRITE;
+       cmd.buffer.block_data[0] = iso_regs[alt][0];
+       cmd.buffer.block_data[1] = iso_regs[alt][1];
+       cmd.buffer.block_data[2] = iso_regs[alt][2];
+       cmd.buffer.block_data[3] = iso_regs[alt][3];
+       cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+       cmd.start = CPIA2_VC_USB_ISOLIM;
+       cmd.reg_count = 4;
+       cpia2_send_command(cam, &cmd);
+
+       /***
+        * Enable relevant streams before starting polling.
+        * First read USB Stream Config Register.
+        ***/
+       cmd.direction = TRANSFER_READ;
+       cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+       cmd.start = CPIA2_VC_USB_STRM;
+       cmd.reg_count = 1;
+       cpia2_send_command(cam, &cmd);
+       reg = cmd.buffer.block_data[0];
+
+       /* Clear iso, bulk, and int */
+       reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE |
+                CPIA2_VC_USB_STRM_ISO_ENABLE |
+                CPIA2_VC_USB_STRM_INT_ENABLE);
+
+       if (alt == USBIF_BULK) {
+               DBG("Enabling bulk xfer\n");
+               reg |= CPIA2_VC_USB_STRM_BLK_ENABLE;    /* Enable Bulk */
+               cam->xfer_mode = XFER_BULK;
+       } else if (alt >= USBIF_ISO_1) {
+               DBG("Enabling ISOC xfer\n");
+               reg |= CPIA2_VC_USB_STRM_ISO_ENABLE;
+               cam->xfer_mode = XFER_ISOC;
+       }
+
+       cmd.buffer.block_data[0] = reg;
+       cmd.direction = TRANSFER_WRITE;
+       cmd.start = CPIA2_VC_USB_STRM;
+       cmd.reg_count = 1;
+       cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
+       cpia2_send_command(cam, &cmd);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ * cpia2_usb_change_streaming_alternate
+ *
+ *****************************************************************************/
+int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
+                                        unsigned int alt)
+{
+       int ret = 0;
+
+       if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6)
+               return -EINVAL;
+
+       if(alt == cam->params.camera_state.stream_mode)
+               return 0;
+
+       cpia2_usb_stream_pause(cam);
+
+       configure_transfer_mode(cam, alt);
+
+       cam->params.camera_state.stream_mode = alt;
+
+       /* Reset the camera to prevent image quality degradation */
+       cpia2_reset_camera(cam);
+
+       cpia2_usb_stream_resume(cam);
+
+       return ret;
+}
+
+/******************************************************************************
+ *
+ * set_alternate
+ *
+ *****************************************************************************/
+int set_alternate(struct camera_data *cam, unsigned int alt)
+{
+       int ret = 0;
+
+       if(alt == cam->cur_alt)
+               return 0;
+
+       if (cam->cur_alt != USBIF_CMDONLY) {
+               DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY);
+               ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY);
+               if (ret != 0)
+                       return ret;
+       }
+       if (alt != USBIF_CMDONLY) {
+               DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt);
+               ret = usb_set_interface(cam->dev, cam->iface, alt);
+               if (ret != 0)
+                       return ret;
+       }
+
+       cam->old_alt = cam->cur_alt;
+       cam->cur_alt = alt;
+
+       return ret;
+}
+
+/******************************************************************************
+ *
+ * free_sbufs
+ *
+ * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL
+ * are assumed to be allocated. Non-NULL .urb members are also assumed to be
+ * submitted (and must therefore be killed before they are freed).
+ *****************************************************************************/
+static void free_sbufs(struct camera_data *cam)
+{
+       int i;
+
+       for (i = 0; i < NUM_SBUF; i++) {
+               if(cam->sbuf[i].urb) {
+                       usb_kill_urb(cam->sbuf[i].urb);
+                       usb_free_urb(cam->sbuf[i].urb);
+                       cam->sbuf[i].urb = NULL;
+               }
+               if(cam->sbuf[i].data) {
+                       kfree(cam->sbuf[i].data);
+                       cam->sbuf[i].data = NULL;
+               }
+       }
+}
+
+/*******
+* Convenience functions
+*******/
+/****************************************************************************
+ *
+ *  write_packet
+ *
+ ***************************************************************************/
+static int write_packet(struct usb_device *udev,
+                       u8 request, u8 * registers, u16 start, size_t size)
+{
+       if (!registers || size <= 0)
+               return -EINVAL;
+
+       return usb_control_msg(udev,
+                              usb_sndctrlpipe(udev, 0),
+                              request,
+                              USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                              start,   /* value */
+                              0,       /* index */
+                              registers,       /* buffer */
+                              size,
+                              HZ);
+}
+
+/****************************************************************************
+ *
+ *  read_packet
+ *
+ ***************************************************************************/
+static int read_packet(struct usb_device *udev,
+                      u8 request, u8 * registers, u16 start, size_t size)
+{
+       if (!registers || size <= 0)
+               return -EINVAL;
+
+       return usb_control_msg(udev,
+                              usb_rcvctrlpipe(udev, 0),
+                              request,
+                              USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
+                              start,   /* value */
+                              0,       /* index */
+                              registers,       /* buffer */
+                              size,
+                              HZ);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_transfer_cmd
+ *
+ *****************************************************************************/
+int cpia2_usb_transfer_cmd(struct camera_data *cam,
+                          void *registers,
+                          u8 request, u8 start, u8 count, u8 direction)
+{
+       int err = 0;
+       struct usb_device *udev = cam->dev;
+
+       if (!udev) {
+               ERR("%s: Internal driver error: udev is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       if (!registers) {
+               ERR("%s: Internal driver error: register array is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       if (direction == TRANSFER_READ) {
+               err = read_packet(udev, request, (u8 *)registers, start, count);
+               if (err > 0)
+                       err = 0;
+       } else if (direction == TRANSFER_WRITE) {
+               err =write_packet(udev, request, (u8 *)registers, start, count);
+               if (err < 0) {
+                       LOG("Control message failed, err val = %d\n", err);
+                       LOG("Message: request = 0x%0X, start = 0x%0X\n",
+                           request, start);
+                       LOG("Message: count = %d, register[0] = 0x%0X\n",
+                           count, ((unsigned char *) registers)[0]);
+               } else
+                       err=0;
+       } else {
+               LOG("Unexpected first byte of direction: %d\n",
+                      direction);
+               return -EINVAL;
+       }
+
+       if(err != 0)
+               LOG("Unexpected error: %d\n", err);
+       return err;
+}
+
+
+/******************************************************************************
+ *
+ *  submit_urbs
+ *
+ *****************************************************************************/
+static int submit_urbs(struct camera_data *cam)
+{
+       struct urb *urb;
+       int fx, err, i;
+
+       for(i=0; i<NUM_SBUF; ++i) {
+               if (cam->sbuf[i].data)
+                       continue;
+               cam->sbuf[i].data =
+                   kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+               if (!cam->sbuf[i].data) {
+                       return -ENOMEM;
+               }
+       }
+
+       /* We double buffer the Isoc lists, and also know the polling
+        * interval is every frame (1 == (1 << (bInterval -1))).
+        */
+       for(i=0; i<NUM_SBUF; ++i) {
+               if(cam->sbuf[i].urb) {
+                       continue;
+               }
+               urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+               if (!urb) {
+                       return -ENOMEM;
+               }
+
+               cam->sbuf[i].urb = urb;
+               urb->dev = cam->dev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = cam->sbuf[i].data;
+               urb->complete = cpia2_usb_complete;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->interval = 1;
+               urb->transfer_buffer_length =
+                       FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+
+               for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+                       urb->iso_frame_desc[fx].offset =
+                               FRAME_SIZE_PER_DESC * fx;
+                       urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+               }
+       }
+
+
+       /* Queue the ISO urbs, and resubmit in the completion handler */
+       for(i=0; i<NUM_SBUF; ++i) {
+               err = usb_submit_urb(cam->sbuf[i].urb, GFP_KERNEL);
+               if (err) {
+                       ERR("usb_submit_urb[%d]() = %d\n", i, err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_start
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate)
+{
+       int ret;
+       int old_alt;
+
+       if(cam->streaming)
+               return 0;
+
+       if (cam->flush) {
+               int i;
+               DBG("Flushing buffers\n");
+               for(i=0; i<cam->num_frames; ++i) {
+                       cam->buffers[i].status = FRAME_EMPTY;
+                       cam->buffers[i].length = 0;
+               }
+               cam->curbuff = &cam->buffers[0];
+               cam->workbuff = cam->curbuff->next;
+               cam->flush = false;
+       }
+
+       old_alt = cam->params.camera_state.stream_mode;
+       cam->params.camera_state.stream_mode = 0;
+       ret = cpia2_usb_change_streaming_alternate(cam, alternate);
+       if (ret < 0) {
+               int ret2;
+               ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret);
+               cam->params.camera_state.stream_mode = old_alt;
+               ret2 = set_alternate(cam, USBIF_CMDONLY);
+               if (ret2 < 0) {
+                       ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already "
+                           "failed. Then tried to call "
+                           "set_alternate(USBIF_CMDONLY) = %d.\n",
+                           alternate, ret, ret2);
+               }
+       } else {
+               cam->frame_count = 0;
+               cam->streaming = 1;
+               ret = cpia2_usb_stream_resume(cam);
+       }
+       return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_pause
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_pause(struct camera_data *cam)
+{
+       int ret = 0;
+       if(cam->streaming) {
+               ret = set_alternate(cam, USBIF_CMDONLY);
+               free_sbufs(cam);
+       }
+       return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_resume
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_resume(struct camera_data *cam)
+{
+       int ret = 0;
+       if(cam->streaming) {
+               cam->first_image_seen = 0;
+               ret = set_alternate(cam, cam->params.camera_state.stream_mode);
+               if(ret == 0) {
+                       ret = submit_urbs(cam);
+               }
+       }
+       return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_stream_stop
+ *
+ *****************************************************************************/
+int cpia2_usb_stream_stop(struct camera_data *cam)
+{
+       int ret;
+       ret = cpia2_usb_stream_pause(cam);
+       cam->streaming = 0;
+       configure_transfer_mode(cam, 0);
+       return ret;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_usb_probe
+ *
+ *  Probe and initialize.
+ *****************************************************************************/
+static int cpia2_usb_probe(struct usb_interface *intf,
+                          const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct usb_interface_descriptor *interface;
+       struct camera_data *cam;
+       int ret;
+
+       /* A multi-config CPiA2 camera? */
+       if (udev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+       interface = &intf->cur_altsetting->desc;
+
+       /* If we get to this point, we found a CPiA2 camera */
+       LOG("CPiA2 USB camera found\n");
+
+       if((cam = cpia2_init_camera_struct()) == NULL)
+               return -ENOMEM;
+
+       cam->dev = udev;
+       cam->iface = interface->bInterfaceNumber;
+
+       ret = set_alternate(cam, USBIF_CMDONLY);
+       if (ret < 0) {
+               ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret);
+               kfree(cam);
+               return ret;
+       }
+
+       if ((ret = cpia2_register_camera(cam)) < 0) {
+               ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
+               kfree(cam);
+               return ret;
+       }
+
+
+       if((ret = cpia2_init_camera(cam)) < 0) {
+               ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
+               cpia2_unregister_camera(cam);
+               kfree(cam);
+               return ret;
+       }
+       LOG("  CPiA Version: %d.%02d (%d.%d)\n",
+              cam->params.version.firmware_revision_hi,
+              cam->params.version.firmware_revision_lo,
+              cam->params.version.asic_id,
+              cam->params.version.asic_rev);
+       LOG("  CPiA PnP-ID: %04x:%04x:%04x\n",
+              cam->params.pnp_id.vendor,
+              cam->params.pnp_id.product,
+              cam->params.pnp_id.device_revision);
+       LOG("  SensorID: %d.(version %d)\n",
+              cam->params.version.sensor_flags,
+              cam->params.version.sensor_rev);
+
+       usb_set_intfdata(intf, cam);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_disconnect
+ *
+ *****************************************************************************/
+static void cpia2_usb_disconnect(struct usb_interface *intf)
+{
+       struct camera_data *cam = usb_get_intfdata(intf);
+       usb_set_intfdata(intf, NULL);
+       cam->present = 0;
+
+       DBG("Stopping stream\n");
+       cpia2_usb_stream_stop(cam);
+
+       DBG("Unregistering camera\n");
+       cpia2_unregister_camera(cam);
+
+       if(cam->buffers) {
+               DBG("Wakeup waiting processes\n");
+               cam->curbuff->status = FRAME_READY;
+               cam->curbuff->length = 0;
+               if (waitqueue_active(&cam->wq_stream))
+                       wake_up_interruptible(&cam->wq_stream);
+       }
+
+       DBG("Releasing interface\n");
+       usb_driver_release_interface(&cpia2_driver, intf);
+
+       if (cam->open_count == 0) {
+               DBG("Freeing camera structure\n");
+               kfree(cam);
+       }
+
+       LOG("CPiA2 camera disconnected.\n");
+}
+
+
+/******************************************************************************
+ *
+ *  usb_cpia2_init
+ *
+ *****************************************************************************/
+int cpia2_usb_init(void)
+{
+       return usb_register(&cpia2_driver);
+}
+
+/******************************************************************************
+ *
+ *  usb_cpia_cleanup
+ *
+ *****************************************************************************/
+void cpia2_usb_cleanup(void)
+{
+       schedule_timeout(2 * HZ);
+       usb_deregister(&cpia2_driver);
+}
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
new file mode 100644 (file)
index 0000000..08f8be3
--- /dev/null
@@ -0,0 +1,2079 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2_v4l.c
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *      Contact:  steve.miller@st.com
+ *  Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com>
+ *
+ *  Description:
+ *     This is a USB driver for CPia2 based video cameras.
+ *     The infrastructure of this driver is based on the cpia usb driver by
+ *     Jochen Scharrlach and Johannes Erdfeldt.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Stripped of 2.4 stuff ready for main kernel submit by
+ *             Alan Cox <alan@redhat.com>
+ ****************************************************************************/
+
+#include <linux/version.h>
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include "cpia2.h"
+#include "cpia2dev.h"
+
+
+//#define _CPIA2_DEBUG_
+
+#define MAKE_STRING_1(x)       #x
+#define MAKE_STRING(x) MAKE_STRING_1(x)
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");
+
+static int buffer_size = 68*1024;
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
+
+static int num_buffers = 3;
+module_param(num_buffers, int, 0);
+MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-"
+                MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)");
+
+static int alternate = DEFAULT_ALT;
+module_param(alternate, int, 0);
+MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-"
+                MAKE_STRING(USBIF_ISO_6) ", default "
+                MAKE_STRING(DEFAULT_ALT) ")");
+
+static int flicker_freq = 60;
+module_param(flicker_freq, int, 0);
+MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or"
+                MAKE_STRING(60) ", default "
+                MAKE_STRING(60) ")");
+
+static int flicker_mode = NEVER_FLICKER;
+module_param(flicker_mode, int, 0);
+MODULE_PARM_DESC(flicker_mode,
+                "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or"
+                MAKE_STRING(ANTI_FLICKER_ON) ", default "
+                MAKE_STRING(NEVER_FLICKER) ")");
+
+MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
+MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
+MODULE_SUPPORTED_DEVICE("video");
+MODULE_LICENSE("GPL");
+
+#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
+
+#ifndef VID_HARDWARE_CPIA2
+#error "VID_HARDWARE_CPIA2 should have been defined in linux/videodev.h"
+#endif
+
+struct control_menu_info {
+       int value;
+       char name[32];
+};
+
+static struct control_menu_info framerate_controls[] =
+{
+       { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" },
+       { CPIA2_VP_FRAMERATE_7_5,  "7.5 fps"  },
+       { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" },
+       { CPIA2_VP_FRAMERATE_15,   "15 fps"   },
+       { CPIA2_VP_FRAMERATE_25,   "25 fps"   },
+       { CPIA2_VP_FRAMERATE_30,   "30 fps"   },
+};
+#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+
+static struct control_menu_info flicker_controls[] =
+{
+       { NEVER_FLICKER, "Off" },
+       { FLICKER_50,    "50 Hz" },
+       { FLICKER_60,    "60 Hz"  },
+};
+#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+
+static struct control_menu_info lights_controls[] =
+{
+       { 0,   "Off" },
+       { 64,  "Top" },
+       { 128, "Bottom"  },
+       { 192, "Both"  },
+};
+#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define GPIO_LIGHTS_MASK 192
+
+static struct v4l2_queryctrl controls[] = {
+       {
+               .id            = V4L2_CID_BRIGHTNESS,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Brightness",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = DEFAULT_BRIGHTNESS,
+       },
+       {
+               .id            = V4L2_CID_CONTRAST,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Contrast",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = DEFAULT_CONTRAST,
+       },
+       {
+               .id            = V4L2_CID_SATURATION,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Saturation",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = DEFAULT_SATURATION,
+       },
+       {
+               .id            = V4L2_CID_HFLIP,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+               .name          = "Mirror Horizontally",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 1,
+               .default_value = 0,
+       },
+       {
+               .id            = V4L2_CID_VFLIP,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+               .name          = "Flip Vertically",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 1,
+               .default_value = 0,
+       },
+       {
+               .id            = CPIA2_CID_TARGET_KB,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Target KB",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = DEFAULT_TARGET_KB,
+       },
+       {
+               .id            = CPIA2_CID_GPIO,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "GPIO",
+               .minimum       = 0,
+               .maximum       = 255,
+               .step          = 1,
+               .default_value = 0,
+       },
+       {
+               .id            = CPIA2_CID_FLICKER_MODE,
+               .type          = V4L2_CTRL_TYPE_MENU,
+               .name          = "Flicker Reduction",
+               .minimum       = 0,
+               .maximum       = NUM_FLICKER_CONTROLS-1,
+               .step          = 1,
+               .default_value = 0,
+       },
+       {
+               .id            = CPIA2_CID_FRAMERATE,
+               .type          = V4L2_CTRL_TYPE_MENU,
+               .name          = "Framerate",
+               .minimum       = 0,
+               .maximum       = NUM_FRAMERATE_CONTROLS-1,
+               .step          = 1,
+               .default_value = NUM_FRAMERATE_CONTROLS-1,
+       },
+       {
+               .id            = CPIA2_CID_USB_ALT,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "USB Alternate",
+               .minimum       = USBIF_ISO_1,
+               .maximum       = USBIF_ISO_6,
+               .step          = 1,
+               .default_value = DEFAULT_ALT,
+       },
+       {
+               .id            = CPIA2_CID_LIGHTS,
+               .type          = V4L2_CTRL_TYPE_MENU,
+               .name          = "Lights",
+               .minimum       = 0,
+               .maximum       = NUM_LIGHTS_CONTROLS-1,
+               .step          = 1,
+               .default_value = 0,
+       },
+       {
+               .id            = CPIA2_CID_RESET_CAMERA,
+               .type          = V4L2_CTRL_TYPE_BUTTON,
+               .name          = "Reset Camera",
+               .minimum       = 0,
+               .maximum       = 0,
+               .step          = 0,
+               .default_value = 0,
+       },
+};
+#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+
+
+/******************************************************************************
+ *
+ *  cpia2_open
+ *
+ *****************************************************************************/
+static int cpia2_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct camera_data *cam = video_get_drvdata(dev);
+       int retval = 0;
+
+       if (!cam) {
+               ERR("Internal error, camera_data not found!\n");
+               return -ENODEV;
+       }
+
+       if(down_interruptible(&cam->busy_lock))
+               return -ERESTARTSYS;
+
+       if(!cam->present) {
+               retval = -ENODEV;
+               goto err_return;
+       }
+
+       if (cam->open_count > 0) {
+               goto skip_init;
+       }
+
+       if (cpia2_allocate_buffers(cam)) {
+               retval = -ENOMEM;
+               goto err_return;
+       }
+
+       /* reset the camera */
+       if (cpia2_reset_camera(cam) < 0) {
+               retval = -EIO;
+               goto err_return;
+       }
+
+       cam->APP_len = 0;
+       cam->COM_len = 0;
+
+skip_init:
+       {
+               struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+               if(!fh) {
+                       retval = -ENOMEM;
+                       goto err_return;
+               }
+               file->private_data = fh;
+               fh->prio = V4L2_PRIORITY_UNSET;
+               v4l2_prio_open(&cam->prio, &fh->prio);
+               fh->mmapped = 0;
+       }
+
+       ++cam->open_count;
+
+       cpia2_dbg_dump_registers(cam);
+
+err_return:
+       up(&cam->busy_lock);
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_close
+ *
+ *****************************************************************************/
+static int cpia2_close(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct camera_data *cam = video_get_drvdata(dev);
+       struct cpia2_fh *fh = file->private_data;
+
+       down(&cam->busy_lock);
+
+       if (cam->present &&
+           (cam->open_count == 1
+            || fh->prio == V4L2_PRIORITY_RECORD
+           )) {
+               cpia2_usb_stream_stop(cam);
+
+               if(cam->open_count == 1) {
+                       /* save camera state for later open */
+                       cpia2_save_camera_state(cam);
+
+                       cpia2_set_low_power(cam);
+                       cpia2_free_buffers(cam);
+               }
+       }
+
+       {
+               if(fh->mmapped)
+                       cam->mmapped = 0;
+               v4l2_prio_close(&cam->prio,&fh->prio);
+               file->private_data = NULL;
+               kfree(fh);
+       }
+
+       if (--cam->open_count == 0) {
+               cpia2_free_buffers(cam);
+               if (!cam->present) {
+                       video_unregister_device(dev);
+                       kfree(cam);
+               }
+       }
+
+       up(&cam->busy_lock);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_v4l_read
+ *
+ *****************************************************************************/
+static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
+                             loff_t *off)
+{
+       struct video_device *dev = video_devdata(file);
+       struct camera_data *cam = video_get_drvdata(dev);
+       int noblock = file->f_flags&O_NONBLOCK;
+
+       struct cpia2_fh *fh = file->private_data;
+
+       if(!cam)
+               return -EINVAL;
+
+       /* Priority check */
+       if(fh->prio != V4L2_PRIORITY_RECORD) {
+               return -EBUSY;
+       }
+
+       return cpia2_read(cam, buf, count, noblock);
+}
+
+
+/******************************************************************************
+ *
+ *  cpia2_v4l_poll
+ *
+ *****************************************************************************/
+static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
+{
+       struct video_device *dev = video_devdata(filp);
+       struct camera_data *cam = video_get_drvdata(dev);
+
+       struct cpia2_fh *fh = filp->private_data;
+
+       if(!cam)
+               return POLLERR;
+
+       /* Priority check */
+       if(fh->prio != V4L2_PRIORITY_RECORD) {
+               return POLLERR;
+       }
+
+       return cpia2_poll(cam, filp, wait);
+}
+
+
+/******************************************************************************
+ *
+ *  ioctl_cap_query
+ *
+ *****************************************************************************/
+static int ioctl_cap_query(void *arg, struct camera_data *cam)
+{
+       struct video_capability *vc;
+       int retval = 0;
+       vc = arg;
+
+       if (cam->params.pnp_id.product == 0x151)
+               strcpy(vc->name, "QX5 Microscope");
+       else
+               strcpy(vc->name, "CPiA2 Camera");
+
+       vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER;
+       vc->channels = 1;
+       vc->audios = 0;
+       vc->minwidth = 176;     /* VIDEOSIZE_QCIF */
+       vc->minheight = 144;
+       switch (cam->params.version.sensor_flags) {
+       case CPIA2_VP_SENSOR_FLAGS_500:
+               vc->maxwidth = STV_IMAGE_VGA_COLS;
+               vc->maxheight = STV_IMAGE_VGA_ROWS;
+               break;
+       case CPIA2_VP_SENSOR_FLAGS_410:
+               vc->maxwidth = STV_IMAGE_CIF_COLS;
+               vc->maxheight = STV_IMAGE_CIF_ROWS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_get_channel
+ *
+ *****************************************************************************/
+static int ioctl_get_channel(void *arg)
+{
+       int retval = 0;
+       struct video_channel *v;
+       v = arg;
+
+       if (v->channel != 0)
+               return -EINVAL;
+
+       v->channel = 0;
+       strcpy(v->name, "Camera");
+       v->tuners = 0;
+       v->flags = 0;
+       v->type = VIDEO_TYPE_CAMERA;
+       v->norm = 0;
+
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_channel
+ *
+ *****************************************************************************/
+static int ioctl_set_channel(void *arg)
+{
+       struct video_channel *v;
+       int retval = 0;
+       v = arg;
+
+       if (retval == 0 && v->channel != 0)
+               retval = -EINVAL;
+
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_image_prop
+ *
+ *****************************************************************************/
+static int ioctl_set_image_prop(void *arg, struct camera_data *cam)
+{
+       struct video_picture *vp;
+       int retval = 0;
+       vp = arg;
+
+       /* brightness, color, contrast need no check 0-65535 */
+       memcpy(&cam->vp, vp, sizeof(*vp));
+
+       /* update cam->params.colorParams */
+       cam->params.color_params.brightness = vp->brightness / 256;
+       cam->params.color_params.saturation = vp->colour / 256;
+       cam->params.color_params.contrast = vp->contrast / 256;
+
+       DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n",
+           cam->params.color_params.brightness,
+           cam->params.color_params.saturation,
+           cam->params.color_params.contrast);
+
+       cpia2_set_color_params(cam);
+
+       return retval;
+}
+
+static int sync(struct camera_data *cam, int frame_nr)
+{
+       struct framebuf *frame = &cam->buffers[frame_nr];
+
+       while (1) {
+               if (frame->status == FRAME_READY)
+                       return 0;
+
+               if (!cam->streaming) {
+                       frame->status = FRAME_READY;
+                       frame->length = 0;
+                       return 0;
+               }
+
+               up(&cam->busy_lock);
+               wait_event_interruptible(cam->wq_stream,
+                                        !cam->streaming ||
+                                        frame->status == FRAME_READY);
+               down(&cam->busy_lock);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+               if(!cam->present)
+                       return -ENOTTY;
+       }
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_window_size
+ *
+ *****************************************************************************/
+static int ioctl_set_window_size(void *arg, struct camera_data *cam,
+                                struct cpia2_fh *fh)
+{
+       /* copy_from_user, check validity, copy to internal structure */
+       struct video_window *vw;
+       int frame, err;
+       vw = arg;
+
+       if (vw->clipcount != 0) /* clipping not supported */
+               return -EINVAL;
+
+       if (vw->clips != NULL)  /* clipping not supported */
+               return -EINVAL;
+
+       /* Ensure that only this process can change the format. */
+       err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+       if(err != 0)
+               return err;
+
+       cam->pixelformat = V4L2_PIX_FMT_JPEG;
+
+       /* Be sure to supply the Huffman tables, this isn't MJPEG */
+       cam->params.compression.inhibit_htables = 0;
+
+       /* we set the video window to something smaller or equal to what
+        * is requested by the user???
+        */
+       DBG("Requested width = %d, height = %d\n", vw->width, vw->height);
+       if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
+               cam->vw.width = vw->width;
+               cam->vw.height = vw->height;
+               cam->params.roi.width = vw->width;
+               cam->params.roi.height = vw->height;
+               cpia2_set_format(cam);
+       }
+
+       for (frame = 0; frame < cam->num_frames; ++frame) {
+               if (cam->buffers[frame].status == FRAME_READING)
+                       if ((err = sync(cam, frame)) < 0)
+                               return err;
+
+               cam->buffers[frame].status = FRAME_EMPTY;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_get_mbuf
+ *
+ *****************************************************************************/
+static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
+{
+       struct video_mbuf *vm;
+       int i;
+       vm = arg;
+
+       memset(vm, 0, sizeof(*vm));
+       vm->size = cam->frame_size*cam->num_frames;
+       vm->frames = cam->num_frames;
+       for (i = 0; i < cam->num_frames; i++)
+               vm->offsets[i] = cam->frame_size * i;
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_mcapture
+ *
+ *****************************************************************************/
+static int ioctl_mcapture(void *arg, struct camera_data *cam,
+                         struct cpia2_fh *fh)
+{
+       struct video_mmap *vm;
+       int video_size, err;
+       vm = arg;
+
+       if (vm->frame < 0 || vm->frame >= cam->num_frames)
+               return -EINVAL;
+
+       /* set video size */
+       video_size = cpia2_match_video_size(vm->width, vm->height);
+       if (cam->video_size < 0) {
+               return -EINVAL;
+       }
+
+       /* Ensure that only this process can change the format. */
+       err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+       if(err != 0)
+               return err;
+
+       if (video_size != cam->video_size) {
+               cam->video_size = video_size;
+               cam->params.roi.width = vm->width;
+               cam->params.roi.height = vm->height;
+               cpia2_set_format(cam);
+       }
+
+       if (cam->buffers[vm->frame].status == FRAME_READING)
+               if ((err=sync(cam, vm->frame)) < 0)
+                       return err;
+
+       cam->buffers[vm->frame].status = FRAME_EMPTY;
+
+       return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode);
+}
+
+/******************************************************************************
+ *
+ *  ioctl_sync
+ *
+ *****************************************************************************/
+static int ioctl_sync(void *arg, struct camera_data *cam)
+{
+       int frame;
+
+       frame = *(int*)arg;
+
+       if (frame < 0 || frame >= cam->num_frames)
+               return -EINVAL;
+
+       return sync(cam, frame);
+}
+
+
+/******************************************************************************
+ *
+ *  ioctl_set_gpio
+ *
+ *****************************************************************************/
+
+static int ioctl_set_gpio(void *arg, struct camera_data *cam)
+{
+       __u32 gpio_val;
+
+       gpio_val = *(__u32*) arg;
+
+       if (gpio_val &~ 0xFFU)
+               return -EINVAL;
+
+       return cpia2_set_gpio(cam, (unsigned char)gpio_val);
+}
+
+/******************************************************************************
+ *
+ *  ioctl_querycap
+ *
+ *  V4L2 device capabilities
+ *
+ *****************************************************************************/
+
+static int ioctl_querycap(void *arg, struct camera_data *cam)
+{
+       struct v4l2_capability *vc = arg;
+
+       memset(vc, 0, sizeof(*vc));
+       strcpy(vc->driver, "cpia2");
+
+       if (cam->params.pnp_id.product == 0x151)
+               strcpy(vc->card, "QX5 Microscope");
+       else
+               strcpy(vc->card, "CPiA2 Camera");
+       switch (cam->params.pnp_id.device_type) {
+       case DEVICE_STV_672:
+               strcat(vc->card, " (672/");
+               break;
+       case DEVICE_STV_676:
+               strcat(vc->card, " (676/");
+               break;
+       default:
+               strcat(vc->card, " (???/");
+               break;
+       }
+       switch (cam->params.version.sensor_flags) {
+       case CPIA2_VP_SENSOR_FLAGS_404:
+               strcat(vc->card, "404)");
+               break;
+       case CPIA2_VP_SENSOR_FLAGS_407:
+               strcat(vc->card, "407)");
+               break;
+       case CPIA2_VP_SENSOR_FLAGS_409:
+               strcat(vc->card, "409)");
+               break;
+       case CPIA2_VP_SENSOR_FLAGS_410:
+               strcat(vc->card, "410)");
+               break;
+       case CPIA2_VP_SENSOR_FLAGS_500:
+               strcat(vc->card, "500)");
+               break;
+       default:
+               strcat(vc->card, "???)");
+               break;
+       }
+
+       if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
+               memset(vc->bus_info,0, sizeof(vc->bus_info));
+
+       vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER,
+                                    CPIA2_PATCH_VER);
+
+       vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+                          V4L2_CAP_READWRITE |
+                          V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_input
+ *
+ *  V4L2 input get/set/enumerate
+ *
+ *****************************************************************************/
+
+static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam)
+{
+       struct v4l2_input *i = arg;
+
+       if(ioclt_nr  != VIDIOC_G_INPUT) {
+               if (i->index != 0)
+                      return -EINVAL;
+       }
+
+       memset(i, 0, sizeof(*i));
+       strcpy(i->name, "Camera");
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_enum_fmt
+ *
+ *  V4L2 format enumerate
+ *
+ *****************************************************************************/
+
+static int ioctl_enum_fmt(void *arg,struct camera_data *cam)
+{
+       struct v4l2_fmtdesc *f = arg;
+       int index = f->index;
+
+       if (index < 0 || index > 1)
+              return -EINVAL;
+
+       memset(f, 0, sizeof(*f));
+       f->index = index;
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       f->flags = V4L2_FMT_FLAG_COMPRESSED;
+       switch(index) {
+       case 0:
+               strcpy(f->description, "MJPEG");
+               f->pixelformat = V4L2_PIX_FMT_MJPEG;
+               break;
+       case 1:
+               strcpy(f->description, "JPEG");
+               f->pixelformat = V4L2_PIX_FMT_JPEG;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_try_fmt
+ *
+ *  V4L2 format try
+ *
+ *****************************************************************************/
+
+static int ioctl_try_fmt(void *arg,struct camera_data *cam)
+{
+       struct v4l2_format *f = arg;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+              return -EINVAL;
+
+       if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
+           f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+              return -EINVAL;
+
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage = cam->frame_size;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+       f->fmt.pix.priv = 0;
+
+       switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) {
+       case VIDEOSIZE_VGA:
+               f->fmt.pix.width = 640;
+               f->fmt.pix.height = 480;
+               break;
+       case VIDEOSIZE_CIF:
+               f->fmt.pix.width = 352;
+               f->fmt.pix.height = 288;
+               break;
+       case VIDEOSIZE_QVGA:
+               f->fmt.pix.width = 320;
+               f->fmt.pix.height = 240;
+               break;
+       case VIDEOSIZE_288_216:
+               f->fmt.pix.width = 288;
+               f->fmt.pix.height = 216;
+               break;
+       case VIDEOSIZE_256_192:
+               f->fmt.pix.width = 256;
+               f->fmt.pix.height = 192;
+               break;
+       case VIDEOSIZE_224_168:
+               f->fmt.pix.width = 224;
+               f->fmt.pix.height = 168;
+               break;
+       case VIDEOSIZE_192_144:
+               f->fmt.pix.width = 192;
+               f->fmt.pix.height = 144;
+               break;
+       case VIDEOSIZE_QCIF:
+       default:
+               f->fmt.pix.width = 176;
+               f->fmt.pix.height = 144;
+               break;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_set_fmt
+ *
+ *  V4L2 format set
+ *
+ *****************************************************************************/
+
+static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh)
+{
+       struct v4l2_format *f = arg;
+       int err, frame;
+
+       err = ioctl_try_fmt(arg, cam);
+       if(err != 0)
+               return err;
+
+       /* Ensure that only this process can change the format. */
+       err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
+       if(err != 0) {
+               return err;
+       }
+
+       cam->pixelformat = f->fmt.pix.pixelformat;
+
+       /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
+        * the missing Huffman table properly. */
+       cam->params.compression.inhibit_htables = 0;
+               /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
+
+       /* we set the video window to something smaller or equal to what
+        * is requested by the user???
+        */
+       DBG("Requested width = %d, height = %d\n",
+           f->fmt.pix.width, f->fmt.pix.height);
+       if (f->fmt.pix.width != cam->vw.width ||
+           f->fmt.pix.height != cam->vw.height) {
+               cam->vw.width = f->fmt.pix.width;
+               cam->vw.height = f->fmt.pix.height;
+               cam->params.roi.width = f->fmt.pix.width;
+               cam->params.roi.height = f->fmt.pix.height;
+               cpia2_set_format(cam);
+       }
+
+       for (frame = 0; frame < cam->num_frames; ++frame) {
+               if (cam->buffers[frame].status == FRAME_READING)
+                       if ((err = sync(cam, frame)) < 0)
+                               return err;
+
+               cam->buffers[frame].status = FRAME_EMPTY;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_get_fmt
+ *
+ *  V4L2 format get
+ *
+ *****************************************************************************/
+
+static int ioctl_get_fmt(void *arg,struct camera_data *cam)
+{
+       struct v4l2_format *f = arg;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+              return -EINVAL;
+
+       f->fmt.pix.width = cam->vw.width;
+       f->fmt.pix.height = cam->vw.height;
+       f->fmt.pix.pixelformat = cam->pixelformat;
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.sizeimage = cam->frame_size;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+       f->fmt.pix.priv = 0;
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_cropcap
+ *
+ *  V4L2 query cropping capabilities
+ *  NOTE: cropping is currently disabled
+ *
+ *****************************************************************************/
+
+static int ioctl_cropcap(void *arg,struct camera_data *cam)
+{
+       struct v4l2_cropcap *c = arg;
+
+       if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+              return -EINVAL;
+
+       c->bounds.left = 0;
+       c->bounds.top = 0;
+       c->bounds.width = cam->vw.width;
+       c->bounds.height = cam->vw.height;
+       c->defrect.left = 0;
+       c->defrect.top = 0;
+       c->defrect.width = cam->vw.width;
+       c->defrect.height = cam->vw.height;
+       c->pixelaspect.numerator = 1;
+       c->pixelaspect.denominator = 1;
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_queryctrl
+ *
+ *  V4L2 query possible control variables
+ *
+ *****************************************************************************/
+
+static int ioctl_queryctrl(void *arg,struct camera_data *cam)
+{
+       struct v4l2_queryctrl *c = arg;
+       int i;
+
+       for(i=0; i<NUM_CONTROLS; ++i) {
+               if(c->id == controls[i].id) {
+                       memcpy(c, controls+i, sizeof(*c));
+                       break;
+               }
+       }
+
+       if(i == NUM_CONTROLS)
+               return -EINVAL;
+
+       /* Some devices have additional limitations */
+       switch(c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               /***
+                * Don't let the register be set to zero - bug in VP4
+                * flash of full brightness
+                ***/
+               if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+                       c->minimum = 1;
+               break;
+       case V4L2_CID_VFLIP:
+               // VP5 Only
+               if(cam->params.pnp_id.device_type == DEVICE_STV_672)
+                       c->flags |= V4L2_CTRL_FLAG_DISABLED;
+               break;
+       case CPIA2_CID_FRAMERATE:
+               if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+                  cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
+                       // Maximum 15fps
+                       int i;
+                       for(i=0; i<c->maximum; ++i) {
+                               if(framerate_controls[i].value ==
+                                  CPIA2_VP_FRAMERATE_15) {
+                                       c->maximum = i;
+                                       c->default_value = i;
+                               }
+                       }
+               }
+               break;
+       case CPIA2_CID_FLICKER_MODE:
+               // Flicker control only valid for 672.
+               if(cam->params.pnp_id.device_type != DEVICE_STV_672)
+                       c->flags |= V4L2_CTRL_FLAG_DISABLED;
+               break;
+       case CPIA2_CID_LIGHTS:
+               // Light control only valid for the QX5 Microscope.
+               if(cam->params.pnp_id.product != 0x151)
+                       c->flags |= V4L2_CTRL_FLAG_DISABLED;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_querymenu
+ *
+ *  V4L2 query possible control variables
+ *
+ *****************************************************************************/
+
+static int ioctl_querymenu(void *arg,struct camera_data *cam)
+{
+       struct v4l2_querymenu *m = arg;
+
+       memset(m->name, 0, sizeof(m->name));
+       m->reserved = 0;
+
+       switch(m->id) {
+       case CPIA2_CID_FLICKER_MODE:
+               if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS)
+                       return -EINVAL;
+
+               strcpy(m->name, flicker_controls[m->index].name);
+               break;
+       case CPIA2_CID_FRAMERATE:
+           {
+               int maximum = NUM_FRAMERATE_CONTROLS - 1;
+               if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+                  cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
+                       // Maximum 15fps
+                       int i;
+                       for(i=0; i<maximum; ++i) {
+                               if(framerate_controls[i].value ==
+                                  CPIA2_VP_FRAMERATE_15)
+                                       maximum = i;
+                       }
+               }
+               if(m->index < 0 || m->index > maximum)
+                       return -EINVAL;
+
+               strcpy(m->name, framerate_controls[m->index].name);
+               break;
+           }
+       case CPIA2_CID_LIGHTS:
+               if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS)
+                       return -EINVAL;
+
+               strcpy(m->name, lights_controls[m->index].name);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_g_ctrl
+ *
+ *  V4L2 get the value of a control variable
+ *
+ *****************************************************************************/
+
+static int ioctl_g_ctrl(void *arg,struct camera_data *cam)
+{
+       struct v4l2_control *c = arg;
+
+       switch(c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS,
+                                TRANSFER_READ, 0);
+               c->value = cam->params.color_params.brightness;
+               break;
+       case V4L2_CID_CONTRAST:
+               cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST,
+                                TRANSFER_READ, 0);
+               c->value = cam->params.color_params.contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION,
+                                TRANSFER_READ, 0);
+               c->value = cam->params.color_params.saturation;
+               break;
+       case V4L2_CID_HFLIP:
+               cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
+                                TRANSFER_READ, 0);
+               c->value = (cam->params.vp_params.user_effects &
+                           CPIA2_VP_USER_EFFECTS_MIRROR) != 0;
+               break;
+       case V4L2_CID_VFLIP:
+               cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
+                                TRANSFER_READ, 0);
+               c->value = (cam->params.vp_params.user_effects &
+                           CPIA2_VP_USER_EFFECTS_FLIP) != 0;
+               break;
+       case CPIA2_CID_TARGET_KB:
+               c->value = cam->params.vc_params.target_kb;
+               break;
+       case CPIA2_CID_GPIO:
+               cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
+                                TRANSFER_READ, 0);
+               c->value = cam->params.vp_params.gpio_data;
+               break;
+       case CPIA2_CID_FLICKER_MODE:
+       {
+               int i, mode;
+               cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
+                                TRANSFER_READ, 0);
+               if(cam->params.flicker_control.cam_register &
+                  CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) {
+                       mode = NEVER_FLICKER;
+               } else {
+                   if(cam->params.flicker_control.cam_register &
+                      CPIA2_VP_FLICKER_MODES_50HZ) {
+                       mode = FLICKER_50;
+                   } else {
+                       mode = FLICKER_60;
+                   }
+               }
+               for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
+                       if(flicker_controls[i].value == mode) {
+                               c->value = i;
+                               break;
+                       }
+               }
+               if(i == NUM_FLICKER_CONTROLS)
+                       return -EINVAL;
+               break;
+       }
+       case CPIA2_CID_FRAMERATE:
+       {
+               int maximum = NUM_FRAMERATE_CONTROLS - 1;
+               int i;
+               for(i=0; i<= maximum; i++) {
+                       if(cam->params.vp_params.frame_rate ==
+                          framerate_controls[i].value)
+                               break;
+               }
+               if(i > maximum)
+                       return -EINVAL;
+               c->value = i;
+               break;
+       }
+       case CPIA2_CID_USB_ALT:
+               c->value = cam->params.camera_state.stream_mode;
+               break;
+       case CPIA2_CID_LIGHTS:
+       {
+               int i;
+               cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
+                                TRANSFER_READ, 0);
+               for(i=0; i<NUM_LIGHTS_CONTROLS; i++) {
+                       if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) ==
+                          lights_controls[i].value) {
+                               break;
+                       }
+               }
+               if(i == NUM_LIGHTS_CONTROLS)
+                       return -EINVAL;
+               c->value = i;
+               break;
+       }
+       case CPIA2_CID_RESET_CAMERA:
+               return -EINVAL;
+       default:
+               return -EINVAL;
+       }
+
+       DBG("Get control id:%d, value:%d\n", c->id, c->value);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_s_ctrl
+ *
+ *  V4L2 set the value of a control variable
+ *
+ *****************************************************************************/
+
+static int ioctl_s_ctrl(void *arg,struct camera_data *cam)
+{
+       struct v4l2_control *c = arg;
+       int i;
+       int retval = 0;
+
+       DBG("Set control id:%d, value:%d\n", c->id, c->value);
+
+       /* Check that the value is in range */
+       for(i=0; i<NUM_CONTROLS; i++) {
+               if(c->id == controls[i].id) {
+                       if(c->value < controls[i].minimum ||
+                          c->value > controls[i].maximum) {
+                               return -EINVAL;
+                       }
+                       break;
+               }
+       }
+       if(i == NUM_CONTROLS)
+               return -EINVAL;
+
+       switch(c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               cpia2_set_brightness(cam, c->value);
+               break;
+       case V4L2_CID_CONTRAST:
+               cpia2_set_contrast(cam, c->value);
+               break;
+       case V4L2_CID_SATURATION:
+               cpia2_set_saturation(cam, c->value);
+               break;
+       case V4L2_CID_HFLIP:
+               cpia2_set_property_mirror(cam, c->value);
+               break;
+       case V4L2_CID_VFLIP:
+               cpia2_set_property_flip(cam, c->value);
+               break;
+       case CPIA2_CID_TARGET_KB:
+               retval = cpia2_set_target_kb(cam, c->value);
+               break;
+       case CPIA2_CID_GPIO:
+               retval = cpia2_set_gpio(cam, c->value);
+               break;
+       case CPIA2_CID_FLICKER_MODE:
+               retval = cpia2_set_flicker_mode(cam,
+                                             flicker_controls[c->value].value);
+               break;
+       case CPIA2_CID_FRAMERATE:
+               retval = cpia2_set_fps(cam, framerate_controls[c->value].value);
+               break;
+       case CPIA2_CID_USB_ALT:
+               retval = cpia2_usb_change_streaming_alternate(cam, c->value);
+               break;
+       case CPIA2_CID_LIGHTS:
+               retval = cpia2_set_gpio(cam, lights_controls[c->value].value);
+               break;
+       case CPIA2_CID_RESET_CAMERA:
+               cpia2_usb_stream_pause(cam);
+               cpia2_reset_camera(cam);
+               cpia2_usb_stream_resume(cam);
+               break;
+       default:
+               retval = -EINVAL;
+       }
+
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_g_jpegcomp
+ *
+ *  V4L2 get the JPEG compression parameters
+ *
+ *****************************************************************************/
+
+static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam)
+{
+       struct v4l2_jpegcompression *parms = arg;
+
+       memset(parms, 0, sizeof(*parms));
+
+       parms->quality = 80; // TODO: Can this be made meaningful?
+
+       parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
+       if(!cam->params.compression.inhibit_htables) {
+               parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
+       }
+
+       parms->APPn = cam->APPn;
+       parms->APP_len = cam->APP_len;
+       if(cam->APP_len > 0) {
+               memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
+               parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
+       }
+
+       parms->COM_len = cam->COM_len;
+       if(cam->COM_len > 0) {
+               memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
+               parms->jpeg_markers |= JPEG_MARKER_COM;
+       }
+
+       DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n",
+           parms->APP_len, parms->COM_len);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_s_jpegcomp
+ *
+ *  V4L2 set the JPEG compression parameters
+ *  NOTE: quality and some jpeg_markers are ignored.
+ *
+ *****************************************************************************/
+
+static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam)
+{
+       struct v4l2_jpegcompression *parms = arg;
+
+       DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n",
+           parms->APP_len, parms->COM_len);
+
+       cam->params.compression.inhibit_htables =
+               !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
+
+       if(parms->APP_len != 0) {
+               if(parms->APP_len > 0 &&
+                  parms->APP_len <= sizeof(cam->APP_data) &&
+                  parms->APPn >= 0 && parms->APPn <= 15) {
+                       cam->APPn = parms->APPn;
+                       cam->APP_len = parms->APP_len;
+                       memcpy(cam->APP_data, parms->APP_data, parms->APP_len);
+               } else {
+                       LOG("Bad APPn Params n=%d len=%d\n",
+                           parms->APPn, parms->APP_len);
+                       return -EINVAL;
+               }
+       } else {
+               cam->APP_len = 0;
+       }
+
+       if(parms->COM_len != 0) {
+               if(parms->COM_len > 0 &&
+                  parms->COM_len <= sizeof(cam->COM_data)) {
+                       cam->COM_len = parms->COM_len;
+                       memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
+               } else {
+                       LOG("Bad COM_len=%d\n", parms->COM_len);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_reqbufs
+ *
+ *  V4L2 Initiate memory mapping.
+ *  NOTE: The user's request is ignored. For now the buffers are fixed.
+ *
+ *****************************************************************************/
+
+static int ioctl_reqbufs(void *arg,struct camera_data *cam)
+{
+       struct v4l2_requestbuffers *req = arg;
+
+       if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+          req->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
+       req->count = cam->num_frames;
+       memset(&req->reserved, 0, sizeof(req->reserved));
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_querybuf
+ *
+ *  V4L2 Query memory buffer status.
+ *
+ *****************************************************************************/
+
+static int ioctl_querybuf(void *arg,struct camera_data *cam)
+{
+       struct v4l2_buffer *buf = arg;
+
+       if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+          buf->index > cam->num_frames)
+               return -EINVAL;
+
+       buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+       buf->length = cam->frame_size;
+
+       buf->memory = V4L2_MEMORY_MMAP;
+
+       if(cam->mmapped)
+               buf->flags = V4L2_BUF_FLAG_MAPPED;
+       else
+               buf->flags = 0;
+
+       switch (cam->buffers[buf->index].status) {
+       case FRAME_EMPTY:
+       case FRAME_ERROR:
+       case FRAME_READING:
+               buf->bytesused = 0;
+               buf->flags = V4L2_BUF_FLAG_QUEUED;
+               break;
+       case FRAME_READY:
+               buf->bytesused = cam->buffers[buf->index].length;
+               buf->timestamp = cam->buffers[buf->index].timestamp;
+               buf->sequence = cam->buffers[buf->index].seq;
+               buf->flags = V4L2_BUF_FLAG_DONE;
+               break;
+       }
+
+       DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
+            buf->index, buf->m.offset, buf->flags, buf->sequence,
+            buf->bytesused);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_qbuf
+ *
+ *  V4L2 User is freeing buffer
+ *
+ *****************************************************************************/
+
+static int ioctl_qbuf(void *arg,struct camera_data *cam)
+{
+       struct v4l2_buffer *buf = arg;
+
+       if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+          buf->memory != V4L2_MEMORY_MMAP ||
+          buf->index > cam->num_frames)
+               return -EINVAL;
+
+       DBG("QBUF #%d\n", buf->index);
+
+       if(cam->buffers[buf->index].status == FRAME_READY)
+               cam->buffers[buf->index].status = FRAME_EMPTY;
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  find_earliest_filled_buffer
+ *
+ *  Helper for ioctl_dqbuf. Find the next ready buffer.
+ *
+ *****************************************************************************/
+
+static int find_earliest_filled_buffer(struct camera_data *cam)
+{
+       int i;
+       int found = -1;
+       for (i=0; i<cam->num_frames; i++) {
+               if(cam->buffers[i].status == FRAME_READY) {
+                       if(found < 0) {
+                               found = i;
+                       } else {
+                               /* find which buffer is earlier */
+                               struct timeval *tv1, *tv2;
+                               tv1 = &cam->buffers[i].timestamp;
+                               tv2 = &cam->buffers[found].timestamp;
+                               if(tv1->tv_sec < tv2->tv_sec ||
+                                  (tv1->tv_sec == tv2->tv_sec &&
+                                   tv1->tv_usec < tv2->tv_usec))
+                                       found = i;
+                       }
+               }
+       }
+       return found;
+}
+
+/******************************************************************************
+ *
+ *  ioctl_dqbuf
+ *
+ *  V4L2 User is asking for a filled buffer.
+ *
+ *****************************************************************************/
+
+static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
+{
+       struct v4l2_buffer *buf = arg;
+       int frame;
+
+       if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+          buf->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       frame = find_earliest_filled_buffer(cam);
+
+       if(frame < 0 && file->f_flags&O_NONBLOCK)
+               return -EAGAIN;
+
+       if(frame < 0) {
+               /* Wait for a frame to become available */
+               struct framebuf *cb=cam->curbuff;
+               up(&cam->busy_lock);
+               wait_event_interruptible(cam->wq_stream,
+                                        !cam->present ||
+                                        (cb=cam->curbuff)->status == FRAME_READY);
+               down(&cam->busy_lock);
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+               if(!cam->present)
+                       return -ENOTTY;
+               frame = cb->num;
+       }
+
+
+       buf->index = frame;
+       buf->bytesused = cam->buffers[buf->index].length;
+       buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+       buf->field = V4L2_FIELD_NONE;
+       buf->timestamp = cam->buffers[buf->index].timestamp;
+       buf->sequence = cam->buffers[buf->index].seq;
+       buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
+       buf->length = cam->frame_size;
+       buf->input = 0;
+       buf->reserved = 0;
+       memset(&buf->timecode, 0, sizeof(buf->timecode));
+
+       DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index,
+           cam->buffers[buf->index].status, buf->sequence, buf->bytesused);
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_ioctl
+ *
+ *****************************************************************************/
+static int cpia2_do_ioctl(struct inode *inode, struct file *file,
+                         unsigned int ioctl_nr, void *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct camera_data *cam = video_get_drvdata(dev);
+       int retval = 0;
+
+       if (!cam)
+               return -ENOTTY;
+
+       /* make this _really_ smp-safe */
+       if (down_interruptible(&cam->busy_lock))
+               return -ERESTARTSYS;
+
+       if (!cam->present) {
+               up(&cam->busy_lock);
+               return -ENODEV;
+       }
+
+       /* Priority check */
+       switch (ioctl_nr) {
+       case VIDIOCSWIN:
+       case VIDIOCMCAPTURE:
+       case VIDIOC_S_FMT:
+       {
+               struct cpia2_fh *fh = file->private_data;
+               retval = v4l2_prio_check(&cam->prio, &fh->prio);
+               if(retval) {
+                       up(&cam->busy_lock);
+                       return retval;
+               }
+               break;
+       }
+       case VIDIOCGMBUF:
+       case VIDIOCSYNC:
+       {
+               struct cpia2_fh *fh = file->private_data;
+               if(fh->prio != V4L2_PRIORITY_RECORD) {
+                       up(&cam->busy_lock);
+                       return -EBUSY;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+       switch (ioctl_nr) {
+       case VIDIOCGCAP:        /* query capabilities */
+               retval = ioctl_cap_query(arg, cam);
+               break;
+
+       case VIDIOCGCHAN:       /* get video source - we are a camera, nothing else */
+               retval = ioctl_get_channel(arg);
+               break;
+       case VIDIOCSCHAN:       /* set video source - we are a camera, nothing else */
+               retval = ioctl_set_channel(arg);
+               break;
+       case VIDIOCGPICT:       /* image properties */
+               memcpy(arg, &cam->vp, sizeof(struct video_picture));
+               break;
+       case VIDIOCSPICT:
+               retval = ioctl_set_image_prop(arg, cam);
+               break;
+       case VIDIOCGWIN:        /* get/set capture window */
+               memcpy(arg, &cam->vw, sizeof(struct video_window));
+               break;
+       case VIDIOCSWIN:
+               retval = ioctl_set_window_size(arg, cam, file->private_data);
+               break;
+       case VIDIOCGMBUF:       /* mmap interface */
+               retval = ioctl_get_mbuf(arg, cam);
+               break;
+       case VIDIOCMCAPTURE:
+               retval = ioctl_mcapture(arg, cam, file->private_data);
+               break;
+       case VIDIOCSYNC:
+               retval = ioctl_sync(arg, cam);
+               break;
+               /* pointless to implement overlay with this camera */
+       case VIDIOCCAPTURE:
+       case VIDIOCGFBUF:
+       case VIDIOCSFBUF:
+       case VIDIOCKEY:
+               retval = -EINVAL;
+               break;
+
+               /* tuner interface - we have none */
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+               retval = -EINVAL;
+               break;
+
+               /* audio interface - we have none */
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               retval = -EINVAL;
+               break;
+
+       /* CPIA2 extension to Video4Linux API */
+       case CPIA2_IOC_SET_GPIO:
+               retval = ioctl_set_gpio(arg, cam);
+               break;
+       case VIDIOC_QUERYCAP:
+               retval = ioctl_querycap(arg,cam);
+               break;
+
+       case VIDIOC_ENUMINPUT:
+       case VIDIOC_G_INPUT:
+       case VIDIOC_S_INPUT:
+               retval = ioctl_input(ioctl_nr, arg,cam);
+               break;
+
+       case VIDIOC_ENUM_FMT:
+               retval = ioctl_enum_fmt(arg,cam);
+               break;
+       case VIDIOC_TRY_FMT:
+               retval = ioctl_try_fmt(arg,cam);
+               break;
+       case VIDIOC_G_FMT:
+               retval = ioctl_get_fmt(arg,cam);
+               break;
+       case VIDIOC_S_FMT:
+               retval = ioctl_set_fmt(arg,cam,file->private_data);
+               break;
+
+       case VIDIOC_CROPCAP:
+               retval = ioctl_cropcap(arg,cam);
+               break;
+       case VIDIOC_G_CROP:
+       case VIDIOC_S_CROP:
+               // TODO: I think cropping can be implemented - SJB
+               retval = -EINVAL;
+               break;
+
+       case VIDIOC_QUERYCTRL:
+               retval = ioctl_queryctrl(arg,cam);
+               break;
+       case VIDIOC_QUERYMENU:
+               retval = ioctl_querymenu(arg,cam);
+               break;
+       case VIDIOC_G_CTRL:
+               retval = ioctl_g_ctrl(arg,cam);
+               break;
+       case VIDIOC_S_CTRL:
+               retval = ioctl_s_ctrl(arg,cam);
+               break;
+
+       case VIDIOC_G_JPEGCOMP:
+               retval = ioctl_g_jpegcomp(arg,cam);
+               break;
+       case VIDIOC_S_JPEGCOMP:
+               retval = ioctl_s_jpegcomp(arg,cam);
+               break;
+
+       case VIDIOC_G_PRIORITY:
+       {
+               struct cpia2_fh *fh = file->private_data;
+               *(enum v4l2_priority*)arg = fh->prio;
+               break;
+       }
+       case VIDIOC_S_PRIORITY:
+       {
+               struct cpia2_fh *fh = file->private_data;
+               enum v4l2_priority prio;
+               prio = *(enum v4l2_priority*)arg;
+               if(cam->streaming &&
+                  prio != fh->prio &&
+                  fh->prio == V4L2_PRIORITY_RECORD) {
+                       /* Can't drop record priority while streaming */
+                       retval = -EBUSY;
+               } else if(prio == V4L2_PRIORITY_RECORD &&
+                  prio != fh->prio &&
+                  v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) {
+                       /* Only one program can record at a time */
+                       retval = -EBUSY;
+               } else {
+                       retval = v4l2_prio_change(&cam->prio, &fh->prio, prio);
+               }
+               break;
+       }
+
+       case VIDIOC_REQBUFS:
+               retval = ioctl_reqbufs(arg,cam);
+               break;
+       case VIDIOC_QUERYBUF:
+               retval = ioctl_querybuf(arg,cam);
+               break;
+       case VIDIOC_QBUF:
+               retval = ioctl_qbuf(arg,cam);
+               break;
+       case VIDIOC_DQBUF:
+               retval = ioctl_dqbuf(arg,cam,file);
+               break;
+       case VIDIOC_STREAMON:
+       {
+               int type;
+               DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
+               type = *(int*)arg;
+               if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       retval = -EINVAL;
+
+               if(!cam->streaming) {
+                       retval = cpia2_usb_stream_start(cam,
+                                         cam->params.camera_state.stream_mode);
+               } else {
+                       retval = -EINVAL;
+               }
+
+               break;
+       }
+       case VIDIOC_STREAMOFF:
+       {
+               int type;
+               DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
+               type = *(int*)arg;
+               if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       retval = -EINVAL;
+
+               if(cam->streaming) {
+                       retval = cpia2_usb_stream_stop(cam);
+               } else {
+                       retval = -EINVAL;
+               }
+
+               break;
+       }
+
+       case VIDIOC_ENUMOUTPUT:
+       case VIDIOC_G_OUTPUT:
+       case VIDIOC_S_OUTPUT:
+       case VIDIOC_G_MODULATOR:
+       case VIDIOC_S_MODULATOR:
+
+       case VIDIOC_ENUMAUDIO:
+       case VIDIOC_G_AUDIO:
+       case VIDIOC_S_AUDIO:
+
+       case VIDIOC_ENUMAUDOUT:
+       case VIDIOC_G_AUDOUT:
+       case VIDIOC_S_AUDOUT:
+
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+
+       case VIDIOC_G_TUNER:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_G_FREQUENCY:
+       case VIDIOC_S_FREQUENCY:
+
+       case VIDIOC_OVERLAY:
+       case VIDIOC_G_FBUF:
+       case VIDIOC_S_FBUF:
+
+       case VIDIOC_G_PARM:
+       case VIDIOC_S_PARM:
+               retval = -EINVAL;
+               break;
+       default:
+               retval = -ENOIOCTLCMD;
+               break;
+       }
+
+       up(&cam->busy_lock);
+       return retval;
+}
+
+static int cpia2_ioctl(struct inode *inode, struct file *file,
+                      unsigned int ioctl_nr, unsigned long iarg)
+{
+       return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl);
+}
+
+/******************************************************************************
+ *
+ *  cpia2_mmap
+ *
+ *****************************************************************************/
+static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
+{
+       int retval;
+       struct video_device *dev = video_devdata(file);
+       struct camera_data *cam = video_get_drvdata(dev);
+
+       /* Priority check */
+       struct cpia2_fh *fh = file->private_data;
+       if(fh->prio != V4L2_PRIORITY_RECORD) {
+               return -EBUSY;
+       }
+
+       retval = cpia2_remap_buffer(cam, area);
+
+       if(!retval)
+               fh->mmapped = 1;
+       return retval;
+}
+
+/******************************************************************************
+ *
+ *  reset_camera_struct_v4l
+ *
+ *  Sets all values to the defaults
+ *****************************************************************************/
+static void reset_camera_struct_v4l(struct camera_data *cam)
+{
+       /***
+        * Fill in the v4l structures.  video_cap is filled in inside the VIDIOCCAP
+        * Ioctl.  Here, just do the window and picture stucts.
+        ***/
+       cam->vp.palette = (u16) VIDEO_PALETTE_RGB24;    /* Is this right? */
+       cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
+       cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
+       cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
+
+       cam->vw.x = 0;
+       cam->vw.y = 0;
+       cam->vw.width = cam->params.roi.width;
+       cam->vw.height = cam->params.roi.height;
+       cam->vw.flags = 0;
+       cam->vw.clipcount = 0;
+
+       cam->frame_size = buffer_size;
+       cam->num_frames = num_buffers;
+
+       /* FlickerModes */
+       cam->params.flicker_control.flicker_mode_req = flicker_mode;
+       cam->params.flicker_control.mains_frequency = flicker_freq;
+
+       /* streamMode */
+       cam->params.camera_state.stream_mode = alternate;
+
+       cam->pixelformat = V4L2_PIX_FMT_JPEG;
+       v4l2_prio_init(&cam->prio);
+       return;
+}
+
+/***
+ * The v4l video device structure initialized for this device
+ ***/
+static struct file_operations fops_template = {
+       .owner=      THIS_MODULE,
+       .open=       cpia2_open,
+       .release=    cpia2_close,
+       .read=       cpia2_v4l_read,
+       .poll=       cpia2_v4l_poll,
+       .ioctl=      cpia2_ioctl,
+       .llseek=     no_llseek,
+       .mmap=       cpia2_mmap,
+};
+
+static struct video_device cpia2_template = {
+       /* I could not find any place for the old .initialize initializer?? */
+       .owner=         THIS_MODULE,
+       .name=          "CPiA2 Camera",
+       .type=          VID_TYPE_CAPTURE,
+       .type2 =        V4L2_CAP_VIDEO_CAPTURE |
+                       V4L2_CAP_STREAMING,
+       .hardware=      VID_HARDWARE_CPIA2,
+       .minor=         -1,
+       .fops=          &fops_template,
+       .release=       video_device_release,
+};
+
+/******************************************************************************
+ *
+ *  cpia2_register_camera
+ *
+ *****************************************************************************/
+int cpia2_register_camera(struct camera_data *cam)
+{
+       cam->vdev = video_device_alloc();
+       if(!cam->vdev)
+               return -ENOMEM;
+
+       memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
+       video_set_drvdata(cam->vdev, cam);
+
+       reset_camera_struct_v4l(cam);
+
+       /* register v4l device */
+       if (video_register_device
+           (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+               ERR("video_register_device failed\n");
+               video_device_release(cam->vdev);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ *  cpia2_unregister_camera
+ *
+ *****************************************************************************/
+void cpia2_unregister_camera(struct camera_data *cam)
+{
+       if (!cam->open_count) {
+               video_unregister_device(cam->vdev);
+       } else {
+               LOG("/dev/video%d removed while open, "
+                   "deferring video_unregister_device\n",
+                   cam->vdev->minor);
+       }
+}
+
+/******************************************************************************
+ *
+ *  check_parameters
+ *
+ *  Make sure that all user-supplied parameters are sensible
+ *****************************************************************************/
+static void __init check_parameters(void)
+{
+       if(buffer_size < PAGE_SIZE) {
+               buffer_size = PAGE_SIZE;
+               LOG("buffer_size too small, setting to %d\n", buffer_size);
+       } else if(buffer_size > 1024*1024) {
+               /* arbitrary upper limiit */
+               buffer_size = 1024*1024;
+               LOG("buffer_size ridiculously large, setting to %d\n",
+                   buffer_size);
+       } else {
+               buffer_size += PAGE_SIZE-1;
+               buffer_size &= ~(PAGE_SIZE-1);
+       }
+
+       if(num_buffers < 1) {
+               num_buffers = 1;
+               LOG("num_buffers too small, setting to %d\n", num_buffers);
+       } else if(num_buffers > VIDEO_MAX_FRAME) {
+               num_buffers = VIDEO_MAX_FRAME;
+               LOG("num_buffers too large, setting to %d\n", num_buffers);
+       }
+
+       if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
+               alternate = DEFAULT_ALT;
+               LOG("alternate specified is invalid, using %d\n", alternate);
+       }
+
+       if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) {
+               flicker_mode = NEVER_FLICKER;
+               LOG("Flicker mode specified is invalid, using %d\n",
+                   flicker_mode);
+       }
+
+       if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) {
+               flicker_freq = FLICKER_60;
+               LOG("Flicker mode specified is invalid, using %d\n",
+                   flicker_freq);
+       }
+
+       if(video_nr < -1 || video_nr > 64) {
+               video_nr = -1;
+               LOG("invalid video_nr specified, must be -1 to 64\n");
+       }
+
+       DBG("Using %d buffers, each %d bytes, alternate=%d\n",
+           num_buffers, buffer_size, alternate);
+}
+
+/************   Module Stuff ***************/
+
+
+/******************************************************************************
+ *
+ * cpia2_init/module_init
+ *
+ *****************************************************************************/
+static int __init cpia2_init(void)
+{
+       LOG("%s v%d.%d.%d\n",
+           ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER);
+       check_parameters();
+       cpia2_usb_init();
+       return 0;
+}
+
+
+/******************************************************************************
+ *
+ * cpia2_exit/module_exit
+ *
+ *****************************************************************************/
+static void __exit cpia2_exit(void)
+{
+       cpia2_usb_cleanup();
+       schedule_timeout(2 * HZ);
+}
+
+module_init(cpia2_init);
+module_exit(cpia2_exit);
+
diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h
new file mode 100644 (file)
index 0000000..d58097c
--- /dev/null
@@ -0,0 +1,50 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2dev.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This file provides definitions for applications wanting to use the
+ *     cpia2 driver beyond the generic v4l capabilities.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef CPIA2_DEV_HEADER
+#define CPIA2_DEV_HEADER
+
+#include <linux/videodev.h>
+
+/***
+ * The following defines are ioctl numbers based on video4linux private ioctls,
+ * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
+ * args
+ */
+#define CPIA2_IOC_SET_GPIO         _IOW('v', BASE_VIDIOCPRIVATE + 17, __u32)
+
+/* V4L2 driver specific controls */
+#define CPIA2_CID_TARGET_KB     (V4L2_CID_PRIVATE_BASE+0)
+#define CPIA2_CID_GPIO          (V4L2_CID_PRIVATE_BASE+1)
+#define CPIA2_CID_FLICKER_MODE  (V4L2_CID_PRIVATE_BASE+2)
+#define CPIA2_CID_FRAMERATE     (V4L2_CID_PRIVATE_BASE+3)
+#define CPIA2_CID_USB_ALT       (V4L2_CID_PRIVATE_BASE+4)
+#define CPIA2_CID_LIGHTS        (V4L2_CID_PRIVATE_BASE+5)
+#define CPIA2_CID_RESET_CAMERA  (V4L2_CID_PRIVATE_BASE+6)
+
+#endif
diff --git a/drivers/media/video/cpia2/cpia2patch.h b/drivers/media/video/cpia2/cpia2patch.h
new file mode 100644 (file)
index 0000000..7f085fb
--- /dev/null
@@ -0,0 +1,233 @@
+/****************************************************************************
+ *
+ *  Filename: cpia2patch.h
+ *
+ *  Copyright 2001, STMicrolectronics, Inc.
+ *
+ *  Contact:  steve.miller@st.com
+ *
+ *  Description:
+ *     This file contains patch data for the CPiA2 (stv0672) VP4.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+#ifndef CPIA2_PATCH_HEADER
+#define CPIA2_PATCH_HEADER
+
+typedef struct {
+       unsigned char reg;
+       unsigned char count;
+       const unsigned char *data;
+} cpia2_patch;
+
+static const unsigned char start_address_hi[1] = {
+       0x01
+};
+
+static const unsigned char start_address_lo[1] = {
+       0xBC
+};
+
+static const unsigned char patch_block0[64] = {
+       0xE3, 0x02, 0xE3, 0x03, 0xE3, 0x04, 0xE3, 0x05,
+       0xE3, 0x06, 0xE3, 0x07, 0x93, 0x44, 0x56, 0xD4,
+       0x93, 0x4E, 0x56, 0x51, 0x93, 0x4E, 0x51, 0xD6,
+       0x93, 0x4E, 0x4F, 0x54, 0x93, 0x4E, 0x92, 0x4F,
+       0x92, 0xA4, 0x93, 0x05, 0x92, 0xF4, 0x93, 0x1B,
+       0x92, 0x92, 0x91, 0xE6, 0x92, 0x36, 0x92, 0x74,
+       0x92, 0x4A, 0x92, 0x8C, 0x92, 0x8E, 0xC8, 0xD0,
+       0x0B, 0x42, 0x02, 0xA0, 0xCA, 0x92, 0x09, 0x02
+};
+
+static const unsigned char patch_block1[64] = {
+       0xC9, 0x10, 0x0A, 0x0A, 0x0A, 0x81, 0xE3, 0xB8,
+       0xE3, 0xB0, 0xE3, 0xA8, 0xE3, 0xA0, 0xE3, 0x98,
+       0xE3, 0x90, 0xE1, 0x00, 0xCF, 0xD7, 0x0A, 0x12,
+       0xCC, 0x95, 0x08, 0xB2, 0x0A, 0x18, 0xE1, 0x00,
+       0x01, 0xEE, 0x0C, 0x08, 0x4A, 0x12, 0xC8, 0x18,
+       0xF0, 0x9A, 0xC0, 0x22, 0xF3, 0x1C, 0x4A, 0x13,
+       0xF3, 0x14, 0xC8, 0xA0, 0xF2, 0x14, 0xF2, 0x1C,
+       0xEB, 0x13, 0xD3, 0xA2, 0x63, 0x16, 0x48, 0x9E
+};
+
+static const unsigned char patch_block2[64] = {
+       0xF0, 0x18, 0xA4, 0x03, 0xF3, 0x93, 0xC0, 0x58,
+       0xF7, 0x13, 0x51, 0x9C, 0xE9, 0x20, 0xCF, 0xEF,
+       0x63, 0xF9, 0x92, 0x2E, 0xD3, 0x5F, 0x63, 0xFA,
+       0x92, 0x2E, 0xD3, 0x67, 0x63, 0xFB, 0x92, 0x2E,
+       0xD3, 0x6F, 0xE9, 0x1A, 0x63, 0x16, 0x48, 0xA7,
+       0xF0, 0x20, 0xA4, 0x06, 0xF3, 0x94, 0xC0, 0x27,
+       0xF7, 0x14, 0xF5, 0x13, 0x51, 0x9D, 0xF6, 0x13,
+       0x63, 0x18, 0xC4, 0x20, 0xCB, 0xEF, 0x63, 0xFC
+};
+
+static const unsigned char patch_block3[64] = {
+       0x92, 0x2E, 0xD3, 0x77, 0x63, 0xFD, 0x92, 0x2E,
+       0xD3, 0x7F, 0x63, 0xFE, 0x92, 0x2E, 0xD3, 0x87,
+       0x63, 0xFF, 0x92, 0x2E, 0xD3, 0x8F, 0x64, 0x38,
+       0x92, 0x2E, 0xD3, 0x97, 0x64, 0x39, 0x92, 0x2E,
+       0xD3, 0x9F, 0xE1, 0x00, 0xF5, 0x3A, 0xF4, 0x3B,
+       0xF7, 0xBF, 0xF2, 0xBC, 0xF2, 0x3D, 0xE1, 0x00,
+       0x80, 0x87, 0x90, 0x80, 0x51, 0xD5, 0x02, 0x22,
+       0x02, 0x32, 0x4B, 0xD3, 0xF7, 0x11, 0x0B, 0xDA
+};
+
+static const unsigned char patch_block4[64] = {
+       0xE1, 0x00, 0x0E, 0x02, 0x02, 0x40, 0x0D, 0xB5,
+       0xE3, 0x02, 0x48, 0x55, 0xE5, 0x12, 0xA4, 0x01,
+       0xE8, 0x1B, 0xE3, 0x90, 0xF0, 0x18, 0xA4, 0x01,
+       0xE8, 0xBF, 0x8D, 0xB8, 0x4B, 0xD1, 0x4B, 0xD8,
+       0x0B, 0xCB, 0x0B, 0xC2, 0xE1, 0x00, 0xE3, 0x02,
+       0xE3, 0x03, 0x52, 0xD3, 0x60, 0x59, 0xE6, 0x93,
+       0x0D, 0x22, 0x52, 0xD4, 0xE6, 0x93, 0x0D, 0x2A,
+       0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, 0x02, 0x5D
+};
+
+static const unsigned char patch_block5[64] = {
+       0x02, 0x63, 0xE3, 0x02, 0xC8, 0x12, 0x02, 0xCA,
+       0xC8, 0x52, 0x02, 0xC2, 0x82, 0x68, 0xE3, 0x02,
+       0xC8, 0x14, 0x02, 0xCA, 0xC8, 0x90, 0x02, 0xC2,
+       0x0A, 0xD0, 0xC9, 0x93, 0x0A, 0xDA, 0xCC, 0xD2,
+       0x0A, 0xE2, 0x63, 0x12, 0x02, 0xDA, 0x0A, 0x98,
+       0x0A, 0xA0, 0x0A, 0xA8, 0xE3, 0x90, 0xE1, 0x00,
+       0xE3, 0x02, 0x0A, 0xD0, 0xC9, 0x93, 0x0A, 0xDA,
+       0xCC, 0xD2, 0x0A, 0xE2, 0x63, 0x12, 0x02, 0xDA
+};
+
+static const unsigned char patch_block6[64] = {
+       0x0A, 0x98, 0x0A, 0xA0, 0x0A, 0xA8, 0x49, 0x91,
+       0xE5, 0x6A, 0xA4, 0x04, 0xC8, 0x12, 0x02, 0xCA,
+       0xC8, 0x52, 0x82, 0x89, 0xC8, 0x14, 0x02, 0xCA,
+       0xC8, 0x90, 0x02, 0xC2, 0xE3, 0x90, 0xE1, 0x00,
+       0x08, 0x60, 0xE1, 0x00, 0x48, 0x53, 0xE8, 0x97,
+       0x08, 0x5A, 0xE1, 0x00, 0xE3, 0x02, 0xE3, 0x03,
+       0x54, 0xD3, 0x60, 0x59, 0xE6, 0x93, 0x0D, 0x52,
+       0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, 0x02, 0x9C
+};
+
+static const unsigned char patch_block7[64] = {
+       0xE3, 0x02, 0x55, 0x13, 0x93, 0x17, 0x55, 0x13,
+       0x93, 0x17, 0xE3, 0x90, 0xE1, 0x00, 0x75, 0x30,
+       0xE3, 0x02, 0xE3, 0x03, 0x55, 0x55, 0x60, 0x59,
+       0xE6, 0x93, 0x0D, 0xB2, 0xE3, 0x98, 0xE3, 0x90,
+       0xE1, 0x00, 0x02, 0xAE, 0xE7, 0x92, 0xE9, 0x18,
+       0xEA, 0x9A, 0xE8, 0x98, 0xE8, 0x10, 0xE8, 0x11,
+       0xE8, 0x51, 0xD2, 0xDA, 0xD2, 0xF3, 0xE8, 0x13,
+       0xD2, 0xFA, 0xE8, 0x50, 0xD2, 0xEA, 0xE8, 0xD0
+};
+
+static const unsigned char patch_block8[64] = {
+       0xE8, 0xD1, 0xD3, 0x0A, 0x03, 0x09, 0x48, 0x23,
+       0xE5, 0x2C, 0xA0, 0x03, 0x48, 0x24, 0xEA, 0x1C,
+       0x03, 0x08, 0xD2, 0xE3, 0xD3, 0x03, 0xD3, 0x13,
+       0xE1, 0x00, 0x02, 0xCB, 0x05, 0x93, 0x57, 0x93,
+       0xF0, 0x9A, 0xAC, 0x0B, 0xE3, 0x07, 0x92, 0xEA,
+       0xE2, 0x9F, 0xE5, 0x06, 0xE3, 0xB0, 0xA0, 0x02,
+       0xEB, 0x1E, 0x82, 0xD7, 0xEA, 0x1E, 0xE2, 0x3B,
+       0x85, 0x9B, 0xE9, 0x1E, 0xC8, 0x90, 0x85, 0x94
+};
+
+static const unsigned char patch_block9[64] = {
+       0x02, 0xDE, 0x05, 0x80, 0x57, 0x93, 0xF0, 0xBA,
+       0xAC, 0x06, 0x92, 0xEA, 0xE2, 0xBF, 0xE5, 0x06,
+       0xA0, 0x01, 0xEB, 0xBF, 0x85, 0x88, 0xE9, 0x3E,
+       0xC8, 0x90, 0x85, 0x81, 0xE9, 0x3E, 0xF0, 0xBA,
+       0xF3, 0x39, 0xF0, 0x3A, 0x60, 0x17, 0xF0, 0x3A,
+       0xC0, 0x90, 0xF0, 0xBA, 0xE1, 0x00, 0x00, 0x3F,
+       0xE3, 0x02, 0xE3, 0x03, 0x58, 0x10, 0x60, 0x59,
+       0xE6, 0x93, 0x0D, 0xA2, 0x58, 0x12, 0xE6, 0x93
+};
+
+static const unsigned char patch_block10[64] = {
+       0x0D, 0xAA, 0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00,
+       0x03, 0x01, 0xE1, 0x00, 0x03, 0x03, 0x9B, 0x7D,
+       0x8B, 0x8B, 0xE3, 0x02, 0xE3, 0x03, 0x58, 0x56,
+       0x60, 0x59, 0xE6, 0x93, 0x0D, 0xBA, 0xE3, 0x98,
+       0xE3, 0x90, 0xE1, 0x00, 0x03, 0x0F, 0x93, 0x11,
+       0xE1, 0x00, 0xE3, 0x02, 0x4A, 0x11, 0x0B, 0x42,
+       0x91, 0xAF, 0xE3, 0x90, 0xE1, 0x00, 0xF2, 0x91,
+       0xF0, 0x91, 0xA3, 0xFE, 0xE1, 0x00, 0x60, 0x92
+};
+
+static const unsigned char patch_block11[64] = {
+       0xC0, 0x5F, 0xF0, 0x13, 0xF0, 0x13, 0x59, 0x5B,
+       0xE2, 0x13, 0xF0, 0x11, 0x5A, 0x19, 0xE2, 0x13,
+       0xE1, 0x00, 0x00, 0x00, 0x03, 0x27, 0x68, 0x61,
+       0x76, 0x61, 0x6E, 0x61, 0x00, 0x06, 0x03, 0x2C,
+       0xE3, 0x02, 0xE3, 0x03, 0xE9, 0x38, 0x59, 0x15,
+       0x59, 0x5A, 0xF2, 0x9A, 0xBC, 0x0B, 0xA4, 0x0A,
+       0x59, 0x1E, 0xF3, 0x11, 0xF0, 0x1A, 0xE2, 0xBB,
+       0x59, 0x15, 0xF0, 0x11, 0x19, 0x2A, 0xE5, 0x02
+};
+
+static const unsigned char patch_block12[54] = {
+       0xA4, 0x01, 0xEB, 0xBF, 0xE3, 0x98, 0xE3, 0x90,
+       0xE1, 0x00, 0x03, 0x42, 0x19, 0x28, 0xE1, 0x00,
+       0xE9, 0x30, 0x60, 0x79, 0xE1, 0x00, 0xE3, 0x03,
+       0xE3, 0x07, 0x60, 0x79, 0x93, 0x4E, 0xE3, 0xB8,
+       0xE3, 0x98, 0xE1, 0x00, 0xE9, 0x1A, 0xF0, 0x1F,
+       0xE2, 0x33, 0xF0, 0x91, 0xE2, 0x92, 0xE0, 0x32,
+       0xF0, 0x31, 0xE1, 0x00, 0x00, 0x00
+};
+
+static const unsigned char do_call[1] = {
+       0x01
+};
+
+
+#define PATCH_DATA_SIZE 18
+
+static const cpia2_patch patch_data[PATCH_DATA_SIZE] = {
+       {0x0A, sizeof(start_address_hi), start_address_hi}
+       ,                       // 0
+       {0x0B, sizeof(start_address_lo), start_address_lo}
+       ,                       // 1
+       {0x0C, sizeof(patch_block0), patch_block0}
+       ,                       // 2
+       {0x0C, sizeof(patch_block1), patch_block1}
+       ,                       // 3
+       {0x0C, sizeof(patch_block2), patch_block2}
+       ,                       // 4
+       {0x0C, sizeof(patch_block3), patch_block3}
+       ,                       // 5
+       {0x0C, sizeof(patch_block4), patch_block4}
+       ,                       // 6
+       {0x0C, sizeof(patch_block5), patch_block5}
+       ,                       // 7
+       {0x0C, sizeof(patch_block6), patch_block6}
+       ,                       // 8
+       {0x0C, sizeof(patch_block7), patch_block7}
+       ,                       // 9
+       {0x0C, sizeof(patch_block8), patch_block8}
+       ,                       // 10
+       {0x0C, sizeof(patch_block9), patch_block9}
+       ,                       //11
+       {0x0C, sizeof(patch_block10), patch_block10}
+       ,                       // 12
+       {0x0C, sizeof(patch_block11), patch_block11}
+       ,                       // 13
+       {0x0C, sizeof(patch_block12), patch_block12}
+       ,                       // 14
+       {0x0A, sizeof(start_address_hi), start_address_hi}
+       ,                       // 15
+       {0x0B, sizeof(start_address_lo), start_address_lo}
+       ,                       // 16
+       {0x0D, sizeof(do_call), do_call}        //17
+};
+
+
+#endif
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig
new file mode 100644 (file)
index 0000000..854264e
--- /dev/null
@@ -0,0 +1,9 @@
+config VIDEO_CX25840
+       tristate "Conexant CX2584x audio/video decoders"
+       depends on VIDEO_DEV && I2C && EXPERIMENTAL
+       select FW_LOADER
+       ---help---
+         Support for the Conexant CX2584x audio/video decoders.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cx25840
index 543ebac..32a896c 100644 (file)
@@ -1,6 +1,6 @@
 cx25840-objs    := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
                   cx25840-vbi.o
 
-obj-$(CONFIG_VIDEO_DECODER) += cx25840.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
 
 EXTRA_CFLAGS += -I$(src)/..
index 5588b9a..8a25797 100644 (file)
@@ -743,6 +743,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 
                memset(input, 0, sizeof(*input));
                input->index = state->aud_input;
+               input->capability = V4L2_AUDCAP_STEREO;
                break;
        }
 
@@ -753,7 +754,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
        case VIDIOC_G_TUNER:
        {
                u8 mode = cx25840_read(client, 0x804);
-               u8 pref = cx25840_read(client, 0x809) & 0xf;
                u8 vpres = cx25840_read(client, 0x80a) & 0x10;
                int val = 0;
 
@@ -773,44 +773,49 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        val |= V4L2_TUNER_SUB_MONO;
 
                if (mode == 2 || mode == 4)
-                       val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+                       val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 
                if (mode & 0x10)
                        val |= V4L2_TUNER_SUB_SAP;
 
                vt->rxsubchans = val;
-
-               switch (pref) {
-               case 0:
-                       vt->audmode = V4L2_TUNER_MODE_MONO;
-                       break;
-               case 1:
-               case 2:
-                       vt->audmode = V4L2_TUNER_MODE_LANG2;
-                       break;
-               case 4:
-               default:
-                       vt->audmode = V4L2_TUNER_MODE_STEREO;
-               }
+               vt->audmode = state->audmode;
                break;
        }
 
        case VIDIOC_S_TUNER:
+               if (state->radio)
+                       break;
+
                switch (vt->audmode) {
                case V4L2_TUNER_MODE_MONO:
-               case V4L2_TUNER_MODE_LANG1:
-                       /* Force PREF_MODE to MONO */
+                       /* mono      -> mono
+                          stereo    -> mono
+                          bilingual -> lang1 */
                        cx25840_and_or(client, 0x809, ~0xf, 0x00);
                        break;
-               case V4L2_TUNER_MODE_STEREO:
-                       /* Force PREF_MODE to STEREO */
+               case V4L2_TUNER_MODE_LANG1:
+                       /* mono      -> mono
+                          stereo    -> stereo
+                          bilingual -> lang1 */
                        cx25840_and_or(client, 0x809, ~0xf, 0x04);
                        break;
+               case V4L2_TUNER_MODE_STEREO:
+                       /* mono      -> mono
+                          stereo    -> stereo
+                          bilingual -> lang1/lang2 */
+                       cx25840_and_or(client, 0x809, ~0xf, 0x07);
+                       break;
                case V4L2_TUNER_MODE_LANG2:
-                       /* Force PREF_MODE to LANG2 */
+                       /* mono      -> mono
+                          stereo    ->stereo
+                          bilingual -> lang2 */
                        cx25840_and_or(client, 0x809, ~0xf, 0x01);
                        break;
+               default:
+                       return -EINVAL;
                }
+               state->audmode = vt->audmode;
                break;
 
        case VIDIOC_G_FMT:
@@ -891,6 +896,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
        state->aud_input = CX25840_AUDIO8;
        state->audclk_freq = 48000;
        state->pvr150_workaround = 0;
+       state->audmode = V4L2_TUNER_MODE_LANG1;
 
        cx25840_initialize(client, 1);
 
index 04d879d..e96fd1f 100644 (file)
@@ -151,7 +151,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
        case VIDIOC_G_FMT:
        {
                static u16 lcr2vbi[] = {
-                       0, V4L2_SLICED_TELETEXT_B, 0,   /* 1 */
+                       0, V4L2_SLICED_TELETEXT_PAL_B, 0,       /* 1 */
                        0, V4L2_SLICED_WSS_625, 0,      /* 4 */
                        V4L2_SLICED_CAPTION_525,        /* 6 */
                        0, 0, V4L2_SLICED_VPS, 0, 0,    /* 9 */
@@ -231,7 +231,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
                for (i = 7; i <= 23; i++) {
                        for (x = 0; x <= 1; x++) {
                                switch (svbi->service_lines[1-x][i]) {
-                               case V4L2_SLICED_TELETEXT_B:
+                               case V4L2_SLICED_TELETEXT_PAL_B:
                                        lcr[i] |= 1 << (4 * x);
                                        break;
                                case V4L2_SLICED_WSS_625:
@@ -282,7 +282,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
 
                switch (id2) {
                case 1:
-                       id2 = V4L2_SLICED_TELETEXT_B;
+                       id2 = V4L2_SLICED_TELETEXT_PAL_B;
                        break;
                case 4:
                        id2 = V4L2_SLICED_WSS_625;
index fd22f30..dd70664 100644 (file)
@@ -78,6 +78,7 @@ struct cx25840_state {
        enum cx25840_video_input vid_input;
        enum cx25840_audio_input aud_input;
        u32 audclk_freq;
+       int audmode;
 };
 
 /* ----------------------------------------------------------------------- */
index 87d79df..e140996 100644 (file)
@@ -50,6 +50,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
        depends on VIDEO_CX88_DVB
        select DVB_MT352
        select VIDEO_CX88_VP3054
+       select DVB_ZL10353
        select DVB_OR51132
        select DVB_CX22702
        select DVB_LGDT330X
@@ -81,6 +82,16 @@ config VIDEO_CX88_VP3054
          which also require support for the VP-3054
          Secondary I2C bus, such at DNTV Live! DVB-T Pro.
 
+config VIDEO_CX88_DVB_ZL10353
+       bool "Zarlink ZL10353 DVB-T Support"
+       default y
+       depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+       select DVB_ZL10353
+       ---help---
+         This adds DVB-T support for cards based on the
+         Connexant 2388x chip and the ZL10353 demodulator,
+         successor to the Zarlink MT352.
+
 config VIDEO_CX88_DVB_OR51132
        bool "OR51132 ATSC Support"
        default y
index 2b90278..6482b9a 100644 (file)
@@ -17,6 +17,7 @@ extra-cflags-$(CONFIG_DVB_CX22702)   += -DHAVE_CX22702=1
 extra-cflags-$(CONFIG_DVB_OR51132)   += -DHAVE_OR51132=1
 extra-cflags-$(CONFIG_DVB_LGDT330X)  += -DHAVE_LGDT330X=1
 extra-cflags-$(CONFIG_DVB_MT352)     += -DHAVE_MT352=1
+extra-cflags-$(CONFIG_DVB_ZL10353)   += -DHAVE_ZL10353=1
 extra-cflags-$(CONFIG_DVB_NXT200X)   += -DHAVE_NXT200X=1
 extra-cflags-$(CONFIG_DVB_CX24123)   += -DHAVE_CX24123=1
 extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
index 2acccd6..bffef1d 100644 (file)
@@ -672,6 +672,11 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
        chip = (snd_cx88_card_t *) card->private_data;
 
        core = cx88_core_get(pci);
+       if (NULL == core) {
+               err = -EINVAL;
+               kfree (chip);
+               return err;
+       }
 
        if (!pci_dma_supported(pci,0xffffffff)) {
                dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
@@ -688,11 +693,6 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
        spin_lock_init(&chip->reg_lock);
 
        cx88_reset(core);
-       if (NULL == core) {
-               err = -EINVAL;
-               kfree (chip);
-               return err;
-       }
        chip->core = core;
 
        /* get irq */
index 1bc9992..c7042cf 100644 (file)
@@ -184,17 +184,18 @@ struct cx88_board cx88_boards[] = {
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-                       .gpio1  = 0x309f,
+                       .gpio1  = 0xe09f,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-                       .gpio1  = 0x305f,
+                       .gpio1  = 0xe05f,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-                       .gpio1  = 0x305f,
+                       .gpio1  = 0xe05f,
                }},
                .radio = {
+                       .gpio1  = 0xe0df,
                        .type   = CX88_RADIO,
                },
        },
@@ -322,19 +323,19 @@ struct cx88_board cx88_boards[] = {
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-                       .gpio0  = 0xff00,
+                       .gpio0  = 0xbff0,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-                       .gpio0  = 0xff03,
+                       .gpio0  = 0xbff3,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-                       .gpio0  = 0xff03,
+                       .gpio0  = 0xbff3,
                }},
                .radio = {
                        .type   = CX88_RADIO,
-                       .gpio0  = 0xff00,
+                       .gpio0  = 0xbff0,
                },
        },
        [CX88_BOARD_ASUS_PVR_416] = {
@@ -1048,6 +1049,50 @@ struct cx88_board cx88_boards[] = {
                }},
                .dvb            = 1,
        },
+       [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
+               /* FIXME: Standard video using the cx88 broadcast decoder is
+                * working, but blackbird isn't working yet, audio is only
+                * working correctly for television mode. S-Video and Composite
+                * are working for video-only, so I have them disabled for now.
+                */
+               .name           = "KWorld HardwareMpegTV XPert",
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x3de2,
+                       .gpio2  = 0x00ff,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x3de6,
+                       .gpio2  = 0x00ff,
+               },
+       },
+       [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
+               .name           = "DViCO FusionHDTV DVB-T Hybrid",
+               .tuner_type     = TUNER_THOMSON_FE6600,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0000a75f,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0000a75b,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0000a75b,
+               }},
+               .dvb            = 1,
+       },
 
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1254,6 +1299,18 @@ struct cx88_subid cx88_subids[] = {
                .subdevice = 0xdb11,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
                /* Re-branded DViCO: UltraView DVB-T Plus */
+       },{
+               .subvendor = 0x17de,
+               .subdevice = 0x0840,
+               .card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
+       },{
+               .subvendor = 0x18ac,
+               .subdevice = 0xdb40,
+               .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+       },{
+               .subvendor = 0x18ac,
+               .subdevice = 0xdb44,
+               .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
        },
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1373,6 +1430,40 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
 }
 
 /* ----------------------------------------------------------------------- */
+/* some DViCO specific stuff                                               */
+
+static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
+{
+       struct i2c_msg msg = { .addr = 0x45, .flags = 0 };
+       int i, err;
+       static u8 init_bufs[13][5] = {
+               { 0x10, 0x00, 0x20, 0x01, 0x03 },
+               { 0x10, 0x10, 0x01, 0x00, 0x21 },
+               { 0x10, 0x10, 0x10, 0x00, 0xCA },
+               { 0x10, 0x10, 0x12, 0x00, 0x08 },
+               { 0x10, 0x10, 0x13, 0x00, 0x0A },
+               { 0x10, 0x10, 0x16, 0x01, 0xC0 },
+               { 0x10, 0x10, 0x22, 0x01, 0x3D },
+               { 0x10, 0x10, 0x73, 0x01, 0x2E },
+               { 0x10, 0x10, 0x72, 0x00, 0xC5 },
+               { 0x10, 0x10, 0x71, 0x01, 0x97 },
+               { 0x10, 0x10, 0x70, 0x00, 0x0F },
+               { 0x10, 0x10, 0xB0, 0x00, 0x01 },
+               { 0x03, 0x0C },
+       };
+
+       for (i = 0; i < 13; i++) {
+               msg.buf = init_bufs[i];
+               msg.len = (i != 12 ? 5 : 2);
+               err = i2c_transfer(&core->i2c_adap, &msg, 1);
+               if (err != 1) {
+                       printk("dvico_fusionhdtv_hybrid_init buf %d failed (err = %d)!\n", i, err);
+                       return;
+               }
+       }
+}
+
+/* ----------------------------------------------------------------------- */
 
 void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
 {
@@ -1438,11 +1529,15 @@ void cx88_card_setup(struct cx88_core *core)
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
                /* GPIO0:0 is hooked to mt352 reset pin */
                cx_set(MO_GP0_IO, 0x00000101);
                cx_clear(MO_GP0_IO, 0x00000001);
                msleep(1);
                cx_set(MO_GP0_IO, 0x00000101);
+               if (0 == core->i2c_rc &&
+                   core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
+                       dvico_fusionhdtv_hybrid_init(core);
                break;
        case CX88_BOARD_KWORLD_DVB_T:
        case CX88_BOARD_DNTV_LIVE_DVB_T:
@@ -1460,7 +1555,7 @@ void cx88_card_setup(struct cx88_core *core)
                if (0 == core->i2c_rc) {
                        /* enable tuner */
                        int i;
-                       u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+                       static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
                        core->i2c_client.addr = 0x0a;
 
                        for (i = 0; i < 5; i++)
index 3720f24..c2cdbaf 100644 (file)
@@ -163,7 +163,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
        return 0;
 }
 
@@ -188,7 +188,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 
        /* save pointer to jmp instruction address */
        risc->jmp = rp;
-       BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size);
+       BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
        return 0;
 }
 
@@ -215,8 +215,7 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
 void
 cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf)
 {
-       if (in_interrupt())
-               BUG();
+       BUG_ON(in_interrupt());
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_pci_unmap(pci, &buf->vb.dma);
        videobuf_dma_free(&buf->vb.dma);
@@ -1061,7 +1060,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
        core->pci_bus  = pci->bus->number;
        core->pci_slot = PCI_SLOT(pci->devfn);
        core->pci_irqmask = 0x00fc00;
-       init_MUTEX(&core->lock);
+       mutex_init(&core->lock);
 
        core->nr = cx88_devcount++;
        sprintf(core->name,"cx88[%d]",core->nr);
index e48aa3f..a9fc269 100644 (file)
@@ -40,6 +40,9 @@
 #  include "cx88-vp3054-i2c.h"
 # endif
 #endif
+#ifdef HAVE_ZL10353
+# include "zl10353.h"
+#endif
 #ifdef HAVE_CX22702
 # include "cx22702.h"
 #endif
@@ -111,6 +114,21 @@ static struct videobuf_queue_ops dvb_qops = {
 
 /* ------------------------------------------------------------------ */
 
+#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
+static int zarlink_pll_set(struct dvb_frontend *fe,
+                             struct dvb_frontend_parameters *params,
+                             u8 *pllbuf)
+{
+       struct cx8802_dev *dev = fe->dvb->priv;
+
+       pllbuf[0] = dev->core->pll_addr << 1;
+       dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+                         params->frequency,
+                         params->u.ofdm.bandwidth);
+       return 0;
+}
+#endif
+
 #ifdef HAVE_MT352
 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
 {
@@ -176,35 +194,22 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int mt352_pll_set(struct dvb_frontend* fe,
-                        struct dvb_frontend_parameters* params,
-                        u8* pllbuf)
-{
-       struct cx8802_dev *dev= fe->dvb->priv;
-
-       pllbuf[0] = dev->core->pll_addr << 1;
-       dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
-                         params->frequency,
-                         params->u.ofdm.bandwidth);
-       return 0;
-}
-
 static struct mt352_config dvico_fusionhdtv = {
        .demod_address = 0x0F,
        .demod_init    = dvico_fusionhdtv_demod_init,
-       .pll_set       = mt352_pll_set,
+       .pll_set       = zarlink_pll_set,
 };
 
 static struct mt352_config dntv_live_dvbt_config = {
        .demod_address = 0x0f,
        .demod_init    = dntv_live_dvbt_demod_init,
-       .pll_set       = mt352_pll_set,
+       .pll_set       = zarlink_pll_set,
 };
 
 static struct mt352_config dvico_fusionhdtv_dual = {
        .demod_address = 0x0F,
        .demod_init    = dvico_dual_demod_init,
-       .pll_set       = mt352_pll_set,
+       .pll_set       = zarlink_pll_set,
 };
 
 #ifdef HAVE_VP3054_I2C
@@ -294,6 +299,46 @@ static struct mt352_config dntv_live_dvbt_pro_config = {
 #endif
 #endif
 
+#ifdef HAVE_ZL10353
+static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
+                                struct dvb_frontend_parameters *params,
+                                u8 *pllbuf)
+{
+       struct cx8802_dev *dev= fe->dvb->priv;
+       struct i2c_msg msg =
+               { .addr = dev->core->pll_addr, .flags = 0,
+                 .buf = pllbuf + 1, .len = 4 };
+       int err;
+
+       pllbuf[0] = dev->core->pll_addr << 1;
+       dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+                         params->frequency,
+                         params->u.ofdm.bandwidth);
+
+       if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+               printk(KERN_WARNING "cx88-dvb: %s error "
+                          "(addr %02x <- %02x, err = %i)\n",
+                          __FUNCTION__, pllbuf[0], pllbuf[1], err);
+               if (err < 0)
+                       return err;
+               else
+                       return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static struct zl10353_config dvico_fusionhdtv_hybrid = {
+       .demod_address = 0x0F,
+       .pll_set       = dvico_hybrid_tune_pll,
+};
+
+static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
+       .demod_address = 0x0F,
+       .pll_set       = zarlink_pll_set,
+};
+#endif
+
 #ifdef HAVE_CX22702
 static struct cx22702_config connexant_refboard_config = {
        .demod_address = 0x43,
@@ -500,16 +545,27 @@ static int dvb_register(struct cx8802_dev *dev)
                                                   &dev->core->i2c_adap);
                break;
 #endif
+#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+               dev->core->pll_addr = 0x60;
+               dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
 #ifdef HAVE_MT352
-       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
-               dev->core->pll_addr = 0x61;
-               dev->core->pll_desc = &dvb_pll_lg_z201;
                dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
                                                 &dev->core->i2c_adap);
+               if (dev->dvb.frontend != NULL)
+                       break;
+#endif
+#ifdef HAVE_ZL10353
+               /* ZL10353 replaces MT352 on later cards */
+               dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+                                                  &dev->core->i2c_adap);
+#endif
                break;
-       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-               dev->core->pll_addr = 0x60;
-               dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
+#endif /* HAVE_MT352 || HAVE_ZL10353 */
+#ifdef HAVE_MT352
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
+               dev->core->pll_addr = 0x61;
+               dev->core->pll_desc = &dvb_pll_lg_z201;
                dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
                                                 &dev->core->i2c_adap);
                break;
@@ -540,6 +596,14 @@ static int dvb_register(struct cx8802_dev *dev)
                                                 &dev->core->i2c_adap);
                break;
 #endif
+#ifdef HAVE_ZL10353
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
+               dev->core->pll_addr = 0x61;
+               dev->core->pll_desc = &dvb_pll_thomson_fe6600;
+               dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
+                                                  &dev->core->i2c_adap);
+               break;
+#endif
 #ifdef HAVE_OR51132
        case CX88_BOARD_PCHDTV_HD3000:
                dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
index 165d948..78a63b7 100644 (file)
 
 /* ---------------------------------------------------------------------- */
 
-/* DigitalNow DNTV Live DVB-T Remote */
-static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
-       [0x00] = KEY_ESC,               /* 'go up a level?' */
-       /* Keys 0 to 9 */
-       [0x0a] = KEY_KP0,
-       [0x01] = KEY_KP1,
-       [0x02] = KEY_KP2,
-       [0x03] = KEY_KP3,
-       [0x04] = KEY_KP4,
-       [0x05] = KEY_KP5,
-       [0x06] = KEY_KP6,
-       [0x07] = KEY_KP7,
-       [0x08] = KEY_KP8,
-       [0x09] = KEY_KP9,
-
-       [0x0b] = KEY_TUNER,             /* tv/fm */
-       [0x0c] = KEY_SEARCH,            /* scan */
-       [0x0d] = KEY_STOP,
-       [0x0e] = KEY_PAUSE,
-       [0x0f] = KEY_LIST,              /* source */
-
-       [0x10] = KEY_MUTE,
-       [0x11] = KEY_REWIND,            /* backward << */
-       [0x12] = KEY_POWER,
-       [0x13] = KEY_S,                 /* snap */
-       [0x14] = KEY_AUDIO,             /* stereo */
-       [0x15] = KEY_CLEAR,             /* reset */
-       [0x16] = KEY_PLAY,
-       [0x17] = KEY_ENTER,
-       [0x18] = KEY_ZOOM,              /* full screen */
-       [0x19] = KEY_FASTFORWARD,       /* forward >> */
-       [0x1a] = KEY_CHANNELUP,
-       [0x1b] = KEY_VOLUMEUP,
-       [0x1c] = KEY_INFO,              /* preview */
-       [0x1d] = KEY_RECORD,            /* record */
-       [0x1e] = KEY_CHANNELDOWN,
-       [0x1f] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* IO-DATA BCTV7E Remote */
-static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
-       [0x40] = KEY_TV,
-       [0x20] = KEY_RADIO,             /* FM */
-       [0x60] = KEY_EPG,
-       [0x00] = KEY_POWER,
-
-       /* Keys 0 to 9 */
-       [0x44] = KEY_KP0,               /* 10 */
-       [0x50] = KEY_KP1,
-       [0x30] = KEY_KP2,
-       [0x70] = KEY_KP3,
-       [0x48] = KEY_KP4,
-       [0x28] = KEY_KP5,
-       [0x68] = KEY_KP6,
-       [0x58] = KEY_KP7,
-       [0x38] = KEY_KP8,
-       [0x78] = KEY_KP9,
-
-       [0x10] = KEY_L,                 /* Live */
-       [0x08] = KEY_T,                 /* Time Shift */
-
-       [0x18] = KEY_PLAYPAUSE,         /* Play */
-
-       [0x24] = KEY_ENTER,             /* 11 */
-       [0x64] = KEY_ESC,               /* 12 */
-       [0x04] = KEY_M,                 /* Multi */
-
-       [0x54] = KEY_VIDEO,
-       [0x34] = KEY_CHANNELUP,
-       [0x74] = KEY_VOLUMEUP,
-       [0x14] = KEY_MUTE,
-
-       [0x4c] = KEY_S,                 /* SVIDEO */
-       [0x2c] = KEY_CHANNELDOWN,
-       [0x6c] = KEY_VOLUMEDOWN,
-       [0x0c] = KEY_ZOOM,
-
-       [0x5c] = KEY_PAUSE,
-       [0x3c] = KEY_C,                 /* || (red) */
-       [0x7c] = KEY_RECORD,            /* recording */
-       [0x1c] = KEY_STOP,
-
-       [0x41] = KEY_REWIND,            /* backward << */
-       [0x21] = KEY_PLAY,
-       [0x61] = KEY_FASTFORWARD,       /* forward >> */
-       [0x01] = KEY_NEXT,              /* skip >| */
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* ADS Tech Instant TV DVB-T PCI Remote */
-static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
-       /* Keys 0 to 9 */
-       [0x4d] = KEY_0,
-       [0x57] = KEY_1,
-       [0x4f] = KEY_2,
-       [0x53] = KEY_3,
-       [0x56] = KEY_4,
-       [0x4e] = KEY_5,
-       [0x5e] = KEY_6,
-       [0x54] = KEY_7,
-       [0x4c] = KEY_8,
-       [0x5c] = KEY_9,
-
-       [0x5b] = KEY_POWER,
-       [0x5f] = KEY_MUTE,
-       [0x55] = KEY_GOTO,
-       [0x5d] = KEY_SEARCH,
-       [0x17] = KEY_EPG,               /* Guide */
-       [0x1f] = KEY_MENU,
-       [0x0f] = KEY_UP,
-       [0x46] = KEY_DOWN,
-       [0x16] = KEY_LEFT,
-       [0x1e] = KEY_RIGHT,
-       [0x0e] = KEY_SELECT,            /* Enter */
-       [0x5a] = KEY_INFO,
-       [0x52] = KEY_EXIT,
-       [0x59] = KEY_PREVIOUS,
-       [0x51] = KEY_NEXT,
-       [0x58] = KEY_REWIND,
-       [0x50] = KEY_FORWARD,
-       [0x44] = KEY_PLAYPAUSE,
-       [0x07] = KEY_STOP,
-       [0x1b] = KEY_RECORD,
-       [0x13] = KEY_TUNER,             /* Live */
-       [0x0a] = KEY_A,
-       [0x12] = KEY_B,
-       [0x03] = KEY_PROG1,             /* 1 */
-       [0x01] = KEY_PROG2,             /* 2 */
-       [0x00] = KEY_PROG3,             /* 3 */
-       [0x06] = KEY_DVD,
-       [0x48] = KEY_AUX,               /* Photo */
-       [0x40] = KEY_VIDEO,
-       [0x19] = KEY_AUDIO,             /* Music */
-       [0x0b] = KEY_CHANNELUP,
-       [0x08] = KEY_CHANNELDOWN,
-       [0x15] = KEY_VOLUMEUP,
-       [0x1c] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* MSI TV@nywhere remote */
-static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
-       /* Keys 0 to 9 */
-       [0x00] = KEY_0,
-       [0x01] = KEY_1,
-       [0x02] = KEY_2,
-       [0x03] = KEY_3,
-       [0x04] = KEY_4,
-       [0x05] = KEY_5,
-       [0x06] = KEY_6,
-       [0x07] = KEY_7,
-       [0x08] = KEY_8,
-       [0x09] = KEY_9,
-
-       [0x0c] = KEY_MUTE,
-       [0x0f] = KEY_SCREEN,            /* Full Screen */
-       [0x10] = KEY_F,                 /* Funtion */
-       [0x11] = KEY_T,                 /* Time shift */
-       [0x12] = KEY_POWER,
-       [0x13] = KEY_MEDIA,             /* MTS */
-       [0x14] = KEY_SLOW,
-       [0x16] = KEY_REWIND,            /* backward << */
-       [0x17] = KEY_ENTER,             /* Return */
-       [0x18] = KEY_FASTFORWARD,       /* forward >> */
-       [0x1a] = KEY_CHANNELUP,
-       [0x1b] = KEY_VOLUMEUP,
-       [0x1e] = KEY_CHANNELDOWN,
-       [0x1f] = KEY_VOLUMEDOWN,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* Cinergy 1400 DVB-T */
-static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
-       [0x01] = KEY_POWER,
-       [0x02] = KEY_1,
-       [0x03] = KEY_2,
-       [0x04] = KEY_3,
-       [0x05] = KEY_4,
-       [0x06] = KEY_5,
-       [0x07] = KEY_6,
-       [0x08] = KEY_7,
-       [0x09] = KEY_8,
-       [0x0a] = KEY_9,
-       [0x0c] = KEY_0,
-
-       [0x0b] = KEY_VIDEO,
-       [0x0d] = KEY_REFRESH,
-       [0x0e] = KEY_SELECT,
-       [0x0f] = KEY_EPG,
-       [0x10] = KEY_UP,
-       [0x11] = KEY_LEFT,
-       [0x12] = KEY_OK,
-       [0x13] = KEY_RIGHT,
-       [0x14] = KEY_DOWN,
-       [0x15] = KEY_TEXT,
-       [0x16] = KEY_INFO,
-
-       [0x17] = KEY_RED,
-       [0x18] = KEY_GREEN,
-       [0x19] = KEY_YELLOW,
-       [0x1a] = KEY_BLUE,
-
-       [0x1b] = KEY_CHANNELUP,
-       [0x1c] = KEY_VOLUMEUP,
-       [0x1d] = KEY_MUTE,
-       [0x1e] = KEY_VOLUMEDOWN,
-       [0x1f] = KEY_CHANNELDOWN,
-
-       [0x40] = KEY_PAUSE,
-       [0x4c] = KEY_PLAY,
-       [0x58] = KEY_RECORD,
-       [0x54] = KEY_PREVIOUS,
-       [0x48] = KEY_STOP,
-       [0x5c] = KEY_NEXT,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* AVERTV STUDIO 303 Remote */
-static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
-       [ 0x2a ] = KEY_KP1,
-       [ 0x32 ] = KEY_KP2,
-       [ 0x3a ] = KEY_KP3,
-       [ 0x4a ] = KEY_KP4,
-       [ 0x52 ] = KEY_KP5,
-       [ 0x5a ] = KEY_KP6,
-       [ 0x6a ] = KEY_KP7,
-       [ 0x72 ] = KEY_KP8,
-       [ 0x7a ] = KEY_KP9,
-       [ 0x0e ] = KEY_KP0,
-
-       [ 0x02 ] = KEY_POWER,
-       [ 0x22 ] = KEY_VIDEO,
-       [ 0x42 ] = KEY_AUDIO,
-       [ 0x62 ] = KEY_ZOOM,
-       [ 0x0a ] = KEY_TV,
-       [ 0x12 ] = KEY_CD,
-       [ 0x1a ] = KEY_TEXT,
-
-       [ 0x16 ] = KEY_SUBTITLE,
-       [ 0x1e ] = KEY_REWIND,
-       [ 0x06 ] = KEY_PRINT,
-
-       [ 0x2e ] = KEY_SEARCH,
-       [ 0x36 ] = KEY_SLEEP,
-       [ 0x3e ] = KEY_SHUFFLE,
-       [ 0x26 ] = KEY_MUTE,
-
-       [ 0x4e ] = KEY_RECORD,
-       [ 0x56 ] = KEY_PAUSE,
-       [ 0x5e ] = KEY_STOP,
-       [ 0x46 ] = KEY_PLAY,
-
-       [ 0x6e ] = KEY_RED,
-       [ 0x0b ] = KEY_GREEN,
-       [ 0x66 ] = KEY_YELLOW,
-       [ 0x03 ] = KEY_BLUE,
-
-       [ 0x76 ] = KEY_LEFT,
-       [ 0x7e ] = KEY_RIGHT,
-       [ 0x13 ] = KEY_DOWN,
-       [ 0x1b ] = KEY_UP,
-};
-
-/* ---------------------------------------------------------------------- */
-
-/* DigitalNow DNTV Live! DVB-T Pro Remote */
-static IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
-       [ 0x16 ] = KEY_POWER,
-       [ 0x5b ] = KEY_HOME,
-
-       [ 0x55 ] = KEY_TV,              /* live tv */
-       [ 0x58 ] = KEY_TUNER,           /* digital Radio */
-       [ 0x5a ] = KEY_RADIO,           /* FM radio */
-       [ 0x59 ] = KEY_DVD,             /* dvd menu */
-       [ 0x03 ] = KEY_1,
-       [ 0x01 ] = KEY_2,
-       [ 0x06 ] = KEY_3,
-       [ 0x09 ] = KEY_4,
-       [ 0x1d ] = KEY_5,
-       [ 0x1f ] = KEY_6,
-       [ 0x0d ] = KEY_7,
-       [ 0x19 ] = KEY_8,
-       [ 0x1b ] = KEY_9,
-       [ 0x0c ] = KEY_CANCEL,
-       [ 0x15 ] = KEY_0,
-       [ 0x4a ] = KEY_CLEAR,
-       [ 0x13 ] = KEY_BACK,
-       [ 0x00 ] = KEY_TAB,
-       [ 0x4b ] = KEY_UP,
-       [ 0x4e ] = KEY_LEFT,
-       [ 0x4f ] = KEY_OK,
-       [ 0x52 ] = KEY_RIGHT,
-       [ 0x51 ] = KEY_DOWN,
-       [ 0x1e ] = KEY_VOLUMEUP,
-       [ 0x0a ] = KEY_VOLUMEDOWN,
-       [ 0x02 ] = KEY_CHANNELDOWN,
-       [ 0x05 ] = KEY_CHANNELUP,
-       [ 0x11 ] = KEY_RECORD,
-       [ 0x14 ] = KEY_PLAY,
-       [ 0x4c ] = KEY_PAUSE,
-       [ 0x1a ] = KEY_STOP,
-       [ 0x40 ] = KEY_REWIND,
-       [ 0x12 ] = KEY_FASTFORWARD,
-       [ 0x41 ] = KEY_PREVIOUSSONG,    /* replay |< */
-       [ 0x42 ] = KEY_NEXTSONG,        /* skip >| */
-       [ 0x54 ] = KEY_CAMERA,          /* capture */
-       [ 0x50 ] = KEY_LANGUAGE,        /* sap */
-       [ 0x47 ] = KEY_TV2,             /* pip */
-       [ 0x4d ] = KEY_SCREEN,
-       [ 0x43 ] = KEY_SUBTITLE,
-       [ 0x10 ] = KEY_MUTE,
-       [ 0x49 ] = KEY_AUDIO,           /* l/r */
-       [ 0x07 ] = KEY_SLEEP,
-       [ 0x08 ] = KEY_VIDEO,           /* a/v */
-       [ 0x0e ] = KEY_PREVIOUS,        /* recall */
-       [ 0x45 ] = KEY_ZOOM,            /* zoom + */
-       [ 0x46 ] = KEY_ANGLE,           /* zoom - */
-       [ 0x56 ] = KEY_RED,
-       [ 0x57 ] = KEY_GREEN,
-       [ 0x5c ] = KEY_YELLOW,
-       [ 0x5d ] = KEY_BLUE,
-};
-
-/* ---------------------------------------------------------------------- */
-
 struct cx88_IR {
        struct cx88_core *core;
        struct input_dev *input;
@@ -517,6 +186,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->mask_keydown = 0x02;
                ir->polling = 5; /* ms */
                break;
+       case CX88_BOARD_PROLINK_PLAYTVPVR:
        case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
                ir_codes = ir_codes_pixelview;
                ir->gpio_addr = MO_GP1_IO;
@@ -524,6 +194,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir->mask_keyup = 0x80;
                ir->polling = 1; /* ms */
                break;
+       case CX88_BOARD_KWORLD_LTV883:
+               ir_codes = ir_codes_pixelview;
+               ir->gpio_addr = MO_GP1_IO;
+               ir->mask_keycode = 0x1f;
+               ir->mask_keyup = 0x60;
+               ir->polling = 1; /* ms */
+               break;
        case CX88_BOARD_ADSTECH_DVB_T_PCI:
                ir_codes = ir_codes_adstech_dvb_t_pci;
                ir->gpio_addr = MO_GP1_IO;
index 073494c..6c97aa7 100644 (file)
@@ -227,7 +227,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0x00,
                        .maximum       = 0xff,
                        .step          = 1,
-                       .default_value = 0,
+                       .default_value = 0x7f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .off                   = 128,
@@ -255,7 +255,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0,
                        .maximum       = 0xff,
                        .step          = 1,
-                       .default_value = 0,
+                       .default_value = 0x7f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .off                   = 128,
@@ -300,7 +300,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
                        .minimum       = 0,
                        .maximum       = 0x3f,
                        .step          = 1,
-                       .default_value = 0x1f,
+                       .default_value = 0x3f,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .reg                   = AUD_VOL_CTL,
@@ -336,17 +336,17 @@ static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bi
                return 1;
 
        /* is it free? */
-       down(&core->lock);
+       mutex_lock(&core->lock);
        if (dev->resources & bit) {
                /* no, someone else uses it */
-               up(&core->lock);
+               mutex_unlock(&core->lock);
                return 0;
        }
        /* it's free, grab it */
        fh->resources  |= bit;
        dev->resources |= bit;
        dprintk(1,"res: get %d\n",bit);
-       up(&core->lock);
+       mutex_unlock(&core->lock);
        return 1;
 }
 
@@ -366,14 +366,13 @@ static
 void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
 {
        struct cx88_core *core = dev->core;
-       if ((fh->resources & bits) != bits)
-               BUG();
+       BUG_ON((fh->resources & bits) != bits);
 
-       down(&core->lock);
+       mutex_lock(&core->lock);
        fh->resources  &= ~bits;
        dev->resources &= ~bits;
        dprintk(1,"res: put %d\n",bits);
-       up(&core->lock);
+       mutex_unlock(&core->lock);
 }
 
 /* ------------------------------------------------------------------ */
@@ -909,7 +908,8 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
        value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
        switch (ctl->id) {
        case V4L2_CID_AUDIO_BALANCE:
-               ctl->value = (value & 0x40) ? (value & 0x3f) : (0x40 - (value & 0x3f));
+               ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40)
+                                       : (0x7f - (value & 0x7f));
                break;
        case V4L2_CID_AUDIO_VOLUME:
                ctl->value = 0x3f - (value & 0x3f);
@@ -918,9 +918,9 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
                ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
                break;
        }
-       printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
-                                       ctl->id, c->reg, ctl->value,
-                                       c->mask, c->sreg ? " [shadowed]" : "");
+       dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+                               ctl->id, c->v.name, ctl->value, c->reg,
+                               value,c->mask, c->sreg ? " [shadowed]" : "");
        return 0;
 }
 
@@ -946,7 +946,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
        mask=c->mask;
        switch (ctl->id) {
        case V4L2_CID_AUDIO_BALANCE:
-               value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value;
+               value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40);
                break;
        case V4L2_CID_AUDIO_VOLUME:
                value = 0x3f - (ctl->value & 0x3f);
@@ -969,9 +969,9 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
                value = ((ctl->value - c->off) << c->shift) & c->mask;
                break;
        }
-       printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
-                                       ctl->id, c->reg, value,
-                                       mask, c->sreg ? " [shadowed]" : "");
+       dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+                               ctl->id, c->v.name, ctl->value, c->reg, value,
+                               mask, c->sreg ? " [shadowed]" : "");
        if (c->sreg) {
                cx_sandor(c->sreg, c->reg, mask, value);
        } else {
@@ -987,8 +987,7 @@ static void init_controls(struct cx88_core *core)
 
        for (i = 0; i < CX8800_CTLS; i++) {
                ctrl.id=cx8800_ctls[i].v.id;
-               ctrl.value=cx8800_ctls[i].v.default_value
-                               +cx8800_ctls[i].off;
+               ctrl.value=cx8800_ctls[i].v.default_value;
                set_control(core, &ctrl);
        }
 }
@@ -1252,7 +1251,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 {
        int err;
 
-       dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
+       dprintk(2, "CORE IOCTL: 0x%x\n", cmd );
        if (video_debug > 1)
                v4l_print_ioctl(core->name,cmd);
 
@@ -1291,9 +1290,9 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
                if (i == ARRAY_SIZE(tvnorms))
                        return -EINVAL;
 
-               down(&core->lock);
+               mutex_lock(&core->lock);
                cx88_set_tvnorm(core,&tvnorms[i]);
-               up(&core->lock);
+               mutex_unlock(&core->lock);
                return 0;
        }
 
@@ -1343,10 +1342,10 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 
                if (*i >= 4)
                        return -EINVAL;
-               down(&core->lock);
+               mutex_lock(&core->lock);
                cx88_newstation(core);
                video_mux(core,*i);
-               up(&core->lock);
+               mutex_unlock(&core->lock);
                return 0;
        }
 
@@ -1438,7 +1437,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
                        return -EINVAL;
                if (1 == radio && f->type != V4L2_TUNER_RADIO)
                        return -EINVAL;
-               down(&core->lock);
+               mutex_lock(&core->lock);
                core->freq = f->frequency;
                cx88_newstation(core);
                cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
@@ -1447,7 +1446,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
                msleep (10);
                cx88_set_tvaudio(core);
 
-               up(&core->lock);
+               mutex_unlock(&core->lock);
                return 0;
        }
 
@@ -1921,11 +1920,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        pci_set_drvdata(pci_dev,dev);
 
        /* initial device configuration */
-       down(&core->lock);
+       mutex_lock(&core->lock);
        cx88_set_tvnorm(core,tvnorms);
        init_controls(core);
        video_mux(core,0);
-       up(&core->lock);
+       mutex_unlock(&core->lock);
 
        /* start tvaudio thread */
        if (core->tuner_type != TUNER_ABSENT)
index e9fd55b..cfa8668 100644 (file)
@@ -35,6 +35,7 @@
 #include "cx88-reg.h"
 
 #include <linux/version.h>
+#include <linux/mutex.h>
 #define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
 
 #ifndef TRUE
@@ -62,7 +63,7 @@
 /* need "shadow" registers for some write-only ones ... */
 #define SHADOW_AUD_VOL_CTL           1
 #define SHADOW_AUD_BAL_CTL           2
-#define SHADOW_MAX                   2
+#define SHADOW_MAX                   3
 
 /* FM Radio deemphasis type */
 enum cx88_deemph_type {
@@ -187,6 +188,8 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_DNTV_LIVE_DVB_T_PRO     42
 #define CX88_BOARD_KWORLD_DVB_T_CX22702    43
 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
+#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -308,8 +311,7 @@ struct cx88_core {
        /* IR remote control state */
        struct cx88_IR             *ir;
 
-       struct semaphore           lock;
-
+       struct mutex               lock;
        /* various v4l controls */
        u32                        freq;
 
index 2831bdd..0fcc935 100644 (file)
@@ -1,6 +1,6 @@
 /*
     dpc7146.c - v4l2 driver for the dpc7146 demonstration board
-    
+
     Copyright (C) 2000-2003 Michael Hunold <michael@mihu.de>
 
     This program is free software; you can redistribute it and/or modify
@@ -52,7 +52,7 @@
 #define SAA711X_DECODED_BYTES_OF_TS_2   0x1C
 #define SAA711X_STATUS_BYTE             0x1F
 
-#define DPC_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0) 
+#define DPC_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
 
 static int debug = 0;
 module_param(debug, int, 0);
@@ -81,16 +81,16 @@ struct dpc
        struct video_device     *video_dev;
        struct video_device     *vbi_dev;
 
-       struct i2c_adapter      i2c_adapter;    
+       struct i2c_adapter      i2c_adapter;
        struct i2c_client       *saa7111a;
-       
+
        int cur_input;  /* current input */
 };
 
 /* fixme: add vbi stuff here */
 static int dpc_probe(struct saa7146_dev* dev)
 {
-       struct dpc* dpc = NULL; 
+       struct dpc* dpc = NULL;
        struct i2c_client *client;
        struct list_head *item;
 
@@ -118,20 +118,20 @@ static int dpc_probe(struct saa7146_dev* dev)
        /* loop through all i2c-devices on the bus and look who is there */
        list_for_each(item,&dpc->i2c_adapter.clients) {
                client = list_entry(item, struct i2c_client, list);
-               if( I2C_SAA7111A == client->addr ) 
+               if( I2C_SAA7111A == client->addr )
                        dpc->saa7111a = client;
        }
 
        /* check if all devices are present */
        if( 0 == dpc->saa7111a ) {
-               DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));    
+               DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
                i2c_del_adapter(&dpc->i2c_adapter);
                kfree(dpc);
                return -ENODEV;
        }
-       
-       /* all devices are present, probe was successful */     
-       DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));  
+
+       /* all devices are present, probe was successful */
+       DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n"));
 
        /* we store the pointer in our private data field */
        dev->ext_priv = dpc;
@@ -182,7 +182,7 @@ static struct saa7146_ext_vv vv_data;
 static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
        struct dpc* dpc = (struct dpc*)dev->ext_priv;
-       
+
        DEB_D(("dpc_v4l2.o: dpc_attach called.\n"));
 
        /* checking for i2c-devices can be omitted here, because we
@@ -193,7 +193,7 @@ static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
                ERR(("cannot register capture v4l2 device. skipping.\n"));
                return -1;
        }
-       
+
        /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
        if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) {
                if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) {
@@ -205,18 +205,18 @@ static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
 
        printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num);
        dpc_num++;
-       
+
        /* the rest */
        dpc->cur_input = 0;
        dpc_init_done(dev);
-       
+
        return 0;
 }
 
 static int dpc_detach(struct saa7146_dev* dev)
 {
        struct dpc* dpc = (struct dpc*)dev->ext_priv;
-       
+
        DEB_EE(("dev:%p\n",dev));
 
        i2c_release_client(dpc->saa7111a);
@@ -238,25 +238,25 @@ static int dpc_detach(struct saa7146_dev* dev)
 int dpc_vbi_bypass(struct saa7146_dev* dev)
 {
        struct dpc* dpc = (struct dpc*)dev->ext_priv;
-       
+
        int i = 1;
 
        /* switch bypass in saa7111a */
        if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) {
                printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n");
                return -1;
-       }                       
+       }
 
        return 0;
 }
 #endif
 
-static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) 
+static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
        struct saa7146_dev *dev = fh->dev;
        struct dpc* dpc = (struct dpc*)dev->ext_priv;
 /*
-       struct saa7146_vv *vv = dev->vv_data; 
+       struct saa7146_vv *vv = dev->vv_data;
 */
        switch(cmd)
        {
@@ -264,11 +264,11 @@ static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        {
                struct v4l2_input *i = arg;
                DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
-               
+
                if( i->index < 0 || i->index >= DPC_INPUTS) {
                        return -EINVAL;
                }
-               
+
                memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input));
 
                DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index));
@@ -289,13 +289,13 @@ static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                if (input < 0 || input >= DPC_INPUTS) {
                        return -EINVAL;
                }
-       
+
                dpc->cur_input = input;
 
                /* fixme: switch input here, switch audio, too! */
 //             saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
                printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n");
-               
+
                return 0;
        }
        default:
@@ -334,8 +334,8 @@ static struct saa7146_standard standard[] = {
 static struct saa7146_extension extension;
 
 static struct saa7146_pci_extension_data dpc = {
-        .ext_priv = "Multimedia eXtension Board",
-        .ext = &extension,
+       .ext_priv = "Multimedia eXtension Board",
+       .ext = &extension,
 };
 
 static struct pci_device_id pci_tbl[] = {
@@ -357,7 +357,7 @@ static struct saa7146_ext_vv vv_data = {
        .capabilities   = V4L2_CAP_VBI_CAPTURE,
        .stds           = &standard[0],
        .num_stds       = sizeof(standard)/sizeof(struct saa7146_standard),
-       .std_callback   = &std_callback, 
+       .std_callback   = &std_callback,
        .ioctls         = &ioctls[0],
        .ioctl          = dpc_ioctl,
 };
@@ -365,7 +365,7 @@ static struct saa7146_ext_vv vv_data = {
 static struct saa7146_extension extension = {
        .name           = "dpc7146 demonstration board",
        .flags          = SAA7146_USE_I2C_IRQ,
-       
+
        .pci_tbl        = &pci_tbl[0],
        .module         = THIS_MODULE,
 
@@ -375,7 +375,7 @@ static struct saa7146_extension extension = {
 
        .irq_mask       = 0,
        .irq_func       = NULL,
-};     
+};
 
 static int __init dpc_init_module(void)
 {
@@ -383,7 +383,7 @@ static int __init dpc_init_module(void)
                DEB_S(("failed to register extension.\n"));
                return -ENODEV;
        }
-       
+
        return 0;
 }
 
index 885fd01..5a793ae 100644 (file)
@@ -5,6 +5,7 @@ config VIDEO_EM28XX
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select VIDEO_IR
+       select VIDEO_SAA711X
        ---help---
          This is a video4linux driver for Empia 28xx based TV cards.
 
index 58f7b41..4e22fc4 100644 (file)
@@ -72,6 +72,24 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = 1,
                }},
        },
+       [EM2820_BOARD_KWORLD_PVRTV2800RF] = {
+               .name         = "Kworld PVR TV 2800 RF",
+               .is_em2800    = 0,
+               .vchannels    = 2,
+               .norm         = VIDEO_MODE_PAL,
+               .tda9887_conf = TDA9887_PRESENT,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_SAA7113,
+               .input           = {{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
        [EM2820_BOARD_TERRATEC_CINERGY_250] = {
                .name         = "Terratec Cinergy 250 USB",
                .vchannels    = 3,
@@ -83,7 +101,7 @@ struct em28xx_board em28xx_boards[] = {
                .input          = {{
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = 2,
-                       .amux     = 0,
+                       .amux     = 1,
                },{
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -257,27 +275,51 @@ struct usb_device_id em28xx_id_table [] = {
        { },
 };
 
+void em28xx_pre_card_setup(struct em28xx *dev)
+{
+       /* request some modules */
+       switch(dev->model){
+               case EM2880_BOARD_TERRATEC_PRODIGY_XS:
+               case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+               case EM2880_BOARD_TERRATEC_HYBRID_XS:
+                       {
+                               em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO?
+                               break;
+                       }
+       }
+}
+
 void em28xx_card_setup(struct em28xx *dev)
 {
        /* request some modules */
-       if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
-               struct tveeprom tv;
+       switch(dev->model){
+               case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+                       {
+                               struct tveeprom tv;
 #ifdef CONFIG_MODULES
-               request_module("tveeprom");
-               request_module("ir-kbd-i2c");
-               request_module("msp3400");
+                               request_module("tveeprom");
+                               request_module("ir-kbd-i2c");
+                               request_module("msp3400");
 #endif
-               /* Call first TVeeprom */
+                               /* Call first TVeeprom */
+
+                               dev->i2c_client.addr = 0xa0 >> 1;
+                               tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
 
-               dev->i2c_client.addr = 0xa0 >> 1;
-               tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+                               dev->tuner_type= tv.tuner_type;
+                               if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+                                       dev->i2s_speed=2048000;
+                                       dev->has_msp34xx=1;
+                               } else
+                                       dev->has_msp34xx=0;
+                               break;
+                       }
+               case EM2820_BOARD_KWORLD_PVRTV2800RF:
+                       {
+                               em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF
+                               break;
+                       }
 
-               dev->tuner_type= tv.tuner_type;
-               if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
-                       dev->i2s_speed=2048000;
-                       dev->has_msp34xx=1;
-               } else
-                       dev->has_msp34xx=0;
        }
 }
 
index 6ca8631..5b6cece 100644 (file)
@@ -420,7 +420,6 @@ static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
                tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
                tun_setup.type = dev->tuner_type;
                tun_setup.addr = dev->tuner_addr;
-
                em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
        }
 
index 30dfa53..31e89e4 100644 (file)
@@ -43,91 +43,6 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 #define dprintk(fmt, arg...)   if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
-       [ 0x01 ] = KEY_CHANNEL,
-       [ 0x02 ] = KEY_SELECT,
-       [ 0x03 ] = KEY_MUTE,
-       [ 0x04 ] = KEY_POWER,
-       [ 0x05 ] = KEY_KP1,
-       [ 0x06 ] = KEY_KP2,
-       [ 0x07 ] = KEY_KP3,
-       [ 0x08 ] = KEY_CHANNELUP,
-       [ 0x09 ] = KEY_KP4,
-       [ 0x0a ] = KEY_KP5,
-       [ 0x0b ] = KEY_KP6,
-       [ 0x0c ] = KEY_CHANNELDOWN,
-       [ 0x0d ] = KEY_KP7,
-       [ 0x0e ] = KEY_KP8,
-       [ 0x0f ] = KEY_KP9,
-       [ 0x10 ] = KEY_VOLUMEUP,
-       [ 0x11 ] = KEY_KP0,
-       [ 0x12 ] = KEY_MENU,
-       [ 0x13 ] = KEY_PRINT,
-       [ 0x14 ] = KEY_VOLUMEDOWN,
-       [ 0x16 ] = KEY_PAUSE,
-       [ 0x18 ] = KEY_RECORD,
-       [ 0x19 ] = KEY_REWIND,
-       [ 0x1a ] = KEY_PLAY,
-       [ 0x1b ] = KEY_FORWARD,
-       [ 0x1c ] = KEY_BACKSPACE,
-       [ 0x1e ] = KEY_STOP,
-       [ 0x40 ] = KEY_ZOOM,
-};
-
-static IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
-       [ 0x3a ] = KEY_KP0,
-       [ 0x31 ] = KEY_KP1,
-       [ 0x32 ] = KEY_KP2,
-       [ 0x33 ] = KEY_KP3,
-       [ 0x34 ] = KEY_KP4,
-       [ 0x35 ] = KEY_KP5,
-       [ 0x36 ] = KEY_KP6,
-       [ 0x37 ] = KEY_KP7,
-       [ 0x38 ] = KEY_KP8,
-       [ 0x39 ] = KEY_KP9,
-
-       [ 0x2f ] = KEY_POWER,
-
-       [ 0x2e ] = KEY_P,
-       [ 0x1f ] = KEY_L,
-       [ 0x2b ] = KEY_I,
-
-       [ 0x2d ] = KEY_ZOOM,
-       [ 0x1e ] = KEY_ZOOM,
-       [ 0x1b ] = KEY_VOLUMEUP,
-       [ 0x0f ] = KEY_VOLUMEDOWN,
-       [ 0x17 ] = KEY_CHANNELUP,
-       [ 0x1c ] = KEY_CHANNELDOWN,
-       [ 0x25 ] = KEY_INFO,
-
-       [ 0x3c ] = KEY_MUTE,
-
-       [ 0x3d ] = KEY_LEFT,
-       [ 0x3b ] = KEY_RIGHT,
-
-       [ 0x3f ] = KEY_UP,
-       [ 0x3e ] = KEY_DOWN,
-       [ 0x1a ] = KEY_PAUSE,
-
-       [ 0x1d ] = KEY_MENU,
-       [ 0x19 ] = KEY_PLAY,
-       [ 0x16 ] = KEY_REWIND,
-       [ 0x13 ] = KEY_FORWARD,
-       [ 0x15 ] = KEY_PAUSE,
-       [ 0x0e ] = KEY_REWIND,
-       [ 0x0d ] = KEY_PLAY,
-       [ 0x0b ] = KEY_STOP,
-       [ 0x07 ] = KEY_FORWARD,
-       [ 0x27 ] = KEY_RECORD,
-       [ 0x26 ] = KEY_TUNER,
-       [ 0x29 ] = KEY_TEXT,
-       [ 0x2a ] = KEY_MEDIA,
-       [ 0x18 ] = KEY_EPG,
-       [ 0x27 ] = KEY_RECORD,
-};
-
 /* ----------------------------------------------------------------------- */
 
 static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
index 5b26780..780342f 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/version.h>
@@ -59,8 +60,14 @@ MODULE_LICENSE("GPL");
 static LIST_HEAD(em28xx_devlist);
 
 static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
 MODULE_PARM_DESC(card,"card type");
+MODULE_PARM_DESC(video_nr,"video device numbers");
+MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
 
 static int tuner = -1;
 module_param(tuner, int, 0444);
@@ -70,6 +77,9 @@ static unsigned int video_debug = 0;
 module_param(video_debug,int,0644);
 MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
 
+/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
+static unsigned long em28xx_devused;
+
 /* supported tv norms */
 static struct em28xx_tvnorm tvnorms[] = {
        {
@@ -91,23 +101,6 @@ static struct em28xx_tvnorm tvnorms[] = {
        }
 };
 
-static const unsigned char saa7114_i2c_init[] = {
-       0x00,0x00,0x01,0x08,0x02,0xc4,0x03,0x30,0x04,0x90,0x05,0x90,0x06,0xeb,0x07,0xe0,
-       0x08,0x88,0x09,0x40,0x0a,0x80,0x0b,0x44,0x0c,0x40,0x0d,0x00,0x0e,0x81,0x0f,0x2a,
-       0x10,0x06,0x11,0x00,0x12,0xc8,0x13,0x80,0x14,0x00,0x15,0x11,0x16,0x01,0x17,0x42,
-       0x18,0x40,0x19,0x80,0x40,0x00,0x41,0xff,0x42,0xff,0x43,0xff,0x44,0xff,0x45,0xff,
-       0x46,0xff,0x47,0xff,0x48,0xff,0x49,0xff,0x4a,0xff,0x4b,0xff,0x4c,0xff,0x4d,0xff,
-       0x4e,0xff,0x4f,0xff,0x50,0xff,0x51,0xff,0x52,0xff,0x53,0xff,0x54,0x5f,0x55,0xff,
-       0x56,0xff,0x57,0xff,0x58,0x00,0x59,0x47,0x5a,0x03,0x5b,0x03,0x5d,0x3e,0x5e,0x00,
-       0x80,0x1c,0x83,0x01,0x84,0xa5,0x85,0x10,0x86,0x45,0x87,0x41,0x88,0xf0,0x88,0x00,
-       0x88,0xf0,0x90,0x00,0x91,0x08,0x92,0x00,0x93,0x80,0x94,0x08,0x95,0x00,0x96,0xc0,
-       0x97,0x02,0x98,0x13,0x99,0x00,0x9a,0x38,0x9b,0x01,0x9c,0x80,0x9d,0x02,0x9e,0x06,
-       0x9f,0x01,0xa0,0x01,0xa1,0x00,0xa2,0x00,0xa4,0x80,0xa5,0x36,0xa6,0x36,0xa8,0x67,
-       0xa9,0x04,0xaa,0x00,0xac,0x33,0xad,0x02,0xae,0x00,0xb0,0xcd,0xb1,0x04,0xb2,0xcd,
-       0xb3,0x04,0xb4,0x01,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00,
-       0xbe,0x00,0xbf,0x00
-};
-
 #define TVNORMS ARRAY_SIZE(tvnorms)
 
 /* supported controls */
@@ -134,65 +127,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
        }
 };
 
-/* FIXME: These are specific to saa711x - should be moved to its code */
-static struct v4l2_queryctrl saa711x_qctrl[] = {
-       {
-               .id = V4L2_CID_BRIGHTNESS,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Brightness",
-               .minimum = -128,
-               .maximum = 127,
-               .step = 1,
-               .default_value = 0,
-               .flags = 0,
-       },{
-               .id = V4L2_CID_CONTRAST,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Contrast",
-               .minimum = 0x0,
-               .maximum = 0x1f,
-               .step = 0x1,
-               .default_value = 0x10,
-               .flags = 0,
-       },{
-               .id = V4L2_CID_SATURATION,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Saturation",
-               .minimum = 0x0,
-               .maximum = 0x1f,
-               .step = 0x1,
-               .default_value = 0x10,
-               .flags = 0,
-       },{
-               .id = V4L2_CID_RED_BALANCE,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Red chroma balance",
-               .minimum = -128,
-               .maximum = 127,
-               .step = 1,
-               .default_value = 0,
-               .flags = 0,
-       },{
-               .id = V4L2_CID_BLUE_BALANCE,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Blue chroma balance",
-               .minimum = -128,
-               .maximum = 127,
-               .step = 1,
-               .default_value = 0,
-               .flags = 0,
-       },{
-               .id = V4L2_CID_GAMMA,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Gamma",
-               .minimum = 0x0,
-               .maximum = 0x3f,
-               .step = 0x1,
-               .default_value = 0x20,
-               .flags = 0,
-       }
-};
-
 static struct usb_driver em28xx_usb_driver;
 
 static DEFINE_MUTEX(em28xx_sysfs_lock);
@@ -211,6 +145,11 @@ static int em28xx_config(struct em28xx *dev)
        em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
 
        /* enable vbi capturing */
+
+/*     em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
+/*     em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
+       em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+
        em28xx_audio_usb_mute(dev, 1);
        dev->mute = 1;          /* maybe not the right place... */
        dev->volume = 0x1f;
@@ -230,22 +169,9 @@ static int em28xx_config(struct em28xx *dev)
 static void em28xx_config_i2c(struct em28xx *dev)
 {
        struct v4l2_frequency f;
-       struct video_decoder_init em28xx_vdi = {.data = NULL };
-
-
-       /* configure decoder */
-       if(dev->model == EM2820_BOARD_MSI_VOX_USB_2){
-               em28xx_vdi.data=saa7114_i2c_init;
-               em28xx_vdi.len=sizeof(saa7114_i2c_init);
-       }
-
-
-       em28xx_i2c_call_clients(dev, DECODER_INIT, &em28xx_vdi);
-       em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &dev->ctl_input);
-/*     em28xx_i2c_call_clients(dev,DECODER_SET_PICTURE, &dev->vpic); */
-/*     em28xx_i2c_call_clients(dev,DECODER_SET_NORM,&dev->tvnorm->id); */
-/*     em28xx_i2c_call_clients(dev,DECODER_ENABLE_OUTPUT,&output); */
-/*     em28xx_i2c_call_clients(dev,DECODER_DUMP, NULL); */
+       em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
+       em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input);
+       em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
 
        /* configure tuner */
        f.tuner = 0;
@@ -285,8 +211,7 @@ static void video_mux(struct em28xx *dev, int index)
        dev->ctl_input = index;
        dev->ctl_ainput = INPUT(index)->amux;
 
-       em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
-
+       em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input);
 
        em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
 
@@ -298,11 +223,11 @@ static void video_mux(struct em28xx *dev, int index)
                em28xx_audio_source(dev, ainput);
        } else {
                switch (dev->ctl_ainput) {
-               case 0:
-                       ainput = EM28XX_AUDIO_SRC_TUNER;
-                       break;
-               default:
-                       ainput = EM28XX_AUDIO_SRC_LINE;
+                       case 0:
+                               ainput = EM28XX_AUDIO_SRC_TUNER;
+                               break;
+                       default:
+                               ainput = EM28XX_AUDIO_SRC_LINE;
                }
                em28xx_audio_source(dev, ainput);
        }
@@ -323,13 +248,20 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
                h = list_entry(list, struct em28xx, devlist);
                if (h->vdev->minor == minor) {
                        dev  = h;
+                       dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               }
+               if (h->vbi_dev->minor == minor) {
+                       dev  = h;
+                       dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
                }
        }
+       if (NULL == dev)
+               return -ENODEV;
 
        filp->private_data=dev;
 
-
-       em28xx_videodbg("users=%d\n", dev->users);
+       em28xx_videodbg("open minor=%d type=%s users=%d\n",
+                               minor,v4l2_type_names[dev->type],dev->users);
 
        if (!down_read_trylock(&em28xx_disconnect))
                return -ERESTARTSYS;
@@ -340,40 +272,36 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
                return -EBUSY;
        }
 
-/*     if(dev->vbi_dev->minor == minor){
-               dev->type=V4L2_BUF_TYPE_VBI_CAPTURE;
-       }*/
-       if (dev->vdev->minor == minor) {
-               dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       }
-
-       init_MUTEX(&dev->fileop_lock);  /* to 1 == available */
+       mutex_init(&dev->fileop_lock);  /* to 1 == available */
        spin_lock_init(&dev->queue_lock);
        init_waitqueue_head(&dev->wait_frame);
        init_waitqueue_head(&dev->wait_stream);
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
 
-       em28xx_set_alternate(dev);
+       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               em28xx_set_alternate(dev);
 
-       dev->width = norm_maxw(dev);
-       dev->height = norm_maxh(dev);
-       dev->frame_size = dev->width * dev->height * 2;
-       dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
-       dev->bytesperline = dev->width * 2;
-       dev->hscale = 0;
-       dev->vscale = 0;
+               dev->width = norm_maxw(dev);
+               dev->height = norm_maxh(dev);
+               dev->frame_size = dev->width * dev->height * 2;
+               dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+               dev->bytesperline = dev->width * 2;
+               dev->hscale = 0;
+               dev->vscale = 0;
 
-       em28xx_capture_start(dev, 1);
-       em28xx_resolution_set(dev);
+               em28xx_capture_start(dev, 1);
+               em28xx_resolution_set(dev);
 
-       /* device needs to be initialized before isoc transfer */
-       video_mux(dev, 0);
+               /* device needs to be initialized before isoc transfer */
+               video_mux(dev, 0);
 
-       /* start the transfer */
-       errCode = em28xx_init_isoc(dev);
-       if (errCode)
-               goto err;
+               /* start the transfer */
+               errCode = em28xx_init_isoc(dev);
+               if (errCode)
+                       goto err;
+
+       }
 
        dev->users++;
        filp->private_data = dev;
@@ -386,10 +314,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 
        dev->state |= DEV_INITIALIZED;
 
-       video_mux(dev, 0);
-
-      err:
-       up(&dev->lock);
+err:
+       mutex_unlock(&dev->lock);
        up_read(&em28xx_disconnect);
        return errCode;
 }
@@ -403,14 +329,21 @@ static void em28xx_release_resources(struct em28xx *dev)
 {
        mutex_lock(&em28xx_sysfs_lock);
 
-       em28xx_info("V4L2 device /dev/video%d deregistered\n",
-                   dev->vdev->minor);
+       /*FIXME: I2C IR should be disconnected */
+
+       em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
+                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
+                               dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
        list_del(&dev->devlist);
        video_unregister_device(dev->vdev);
-/*     video_unregister_device(dev->vbi_dev); */
+       video_unregister_device(dev->vbi_dev);
        em28xx_i2c_unregister(dev);
        usb_put_dev(dev->udev);
        mutex_unlock(&em28xx_sysfs_lock);
+
+
+       /* Mark device as unused */
+       em28xx_devused&=~(1<<dev->devno);
 }
 
 /*
@@ -424,7 +357,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
 
        em28xx_videodbg("users=%d\n", dev->users);
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
 
        em28xx_uninit_isoc(dev);
 
@@ -433,7 +366,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
        /* the device is already disconnect, free the remaining resources */
        if (dev->state & DEV_DISCONNECTED) {
                em28xx_release_resources(dev);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                kfree(dev);
                return 0;
        }
@@ -449,7 +382,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
 
        dev->users--;
        wake_up_interruptible_nr(&dev->open, 1);
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -466,32 +399,54 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
        int ret = 0;
        struct em28xx *dev = filp->private_data;
 
-       if (down_interruptible(&dev->fileop_lock))
+       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
+       }
+       if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
+               em28xx_videodbg("not supported yet! ...\n");
+               if (copy_to_user(buf, "", 1)) {
+                       mutex_unlock(&dev->fileop_lock);
+                       return -EFAULT;
+               }
+               return (1);
+       }
+       if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+               em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
+               em28xx_videodbg("not supported yet! ...\n");
+               if (copy_to_user(buf, "", 1)) {
+                       mutex_unlock(&dev->fileop_lock);
+                       return -EFAULT;
+               }
+               return (1);
+       }
+
+       if (mutex_lock_interruptible(&dev->fileop_lock))
                return -ERESTARTSYS;
 
        if (dev->state & DEV_DISCONNECTED) {
                em28xx_videodbg("device not present\n");
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -ENODEV;
        }
 
        if (dev->state & DEV_MISCONFIGURED) {
                em28xx_videodbg("device misconfigured; close and open it again\n");
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -EIO;
        }
 
        if (dev->io == IO_MMAP) {
                em28xx_videodbg ("IO method is set to mmap; close and open"
                                " the device again to choose the read method\n");
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -EINVAL;
        }
 
        if (dev->io == IO_NONE) {
                if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
                        em28xx_errdev("read failed, not enough memory\n");
-                       up(&dev->fileop_lock);
+                       mutex_unlock(&dev->fileop_lock);
                        return -ENOMEM;
                }
                dev->io = IO_READ;
@@ -500,13 +455,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
        }
 
        if (!count) {
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return 0;
        }
 
        if (list_empty(&dev->outqueue)) {
                if (filp->f_flags & O_NONBLOCK) {
-                       up(&dev->fileop_lock);
+                       mutex_unlock(&dev->fileop_lock);
                        return -EAGAIN;
                }
                ret = wait_event_interruptible
@@ -514,11 +469,11 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
                     (!list_empty(&dev->outqueue)) ||
                     (dev->state & DEV_DISCONNECTED));
                if (ret) {
-                       up(&dev->fileop_lock);
+                       mutex_unlock(&dev->fileop_lock);
                        return ret;
                }
                if (dev->state & DEV_DISCONNECTED) {
-                       up(&dev->fileop_lock);
+                       mutex_unlock(&dev->fileop_lock);
                        return -ENODEV;
                }
        }
@@ -537,12 +492,12 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
                count = f->buf.length;
 
        if (copy_to_user(buf, f->bufmem, count)) {
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -EFAULT;
        }
        *f_pos += count;
 
-       up(&dev->fileop_lock);
+       mutex_unlock(&dev->fileop_lock);
 
        return count;
 }
@@ -556,7 +511,7 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
        unsigned int mask = 0;
        struct em28xx *dev = filp->private_data;
 
-       if (down_interruptible(&dev->fileop_lock))
+       if (mutex_lock_interruptible(&dev->fileop_lock))
                return POLLERR;
 
        if (dev->state & DEV_DISCONNECTED) {
@@ -582,13 +537,13 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
                        if (!list_empty(&dev->outqueue))
                                mask |= POLLIN | POLLRDNORM;
 
-                       up(&dev->fileop_lock);
+                       mutex_unlock(&dev->fileop_lock);
 
                        return mask;
                }
        }
 
-       up(&dev->fileop_lock);
+       mutex_unlock(&dev->fileop_lock);
        return POLLERR;
 }
 
@@ -628,25 +583,25 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 
        struct em28xx *dev = filp->private_data;
 
-       if (down_interruptible(&dev->fileop_lock))
+       if (mutex_lock_interruptible(&dev->fileop_lock))
                return -ERESTARTSYS;
 
        if (dev->state & DEV_DISCONNECTED) {
                em28xx_videodbg("mmap: device not present\n");
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -ENODEV;
        }
 
        if (dev->state & DEV_MISCONFIGURED) {
                em28xx_videodbg ("mmap: Device is misconfigured; close and "
                                                "open it again\n");
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -EIO;
        }
 
        if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
            size != PAGE_ALIGN(dev->frame[0].buf.length)) {
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -EINVAL;
        }
 
@@ -656,7 +611,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        }
        if (i == dev->num_frames) {
                em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -EINVAL;
        }
 
@@ -668,7 +623,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        while (size > 0) {      /* size is page-aligned */
                if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
                        em28xx_videodbg("mmap: vm_insert_page failed\n");
-                       up(&dev->fileop_lock);
+                       mutex_unlock(&dev->fileop_lock);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -680,7 +635,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        vma->vm_private_data = &dev->frame[i];
 
        em28xx_vm_open(vma);
-       up(&dev->fileop_lock);
+       mutex_unlock(&dev->fileop_lock);
        return 0;
 }
 
@@ -702,43 +657,6 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
        }
 }
 
-/*FIXME: should be moved to saa711x */
-static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
-{
-       s32 tmp;
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               if ((tmp = em28xx_brightness_get(dev)) < 0)
-                       return -EIO;
-               ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
-               return 0;
-       case V4L2_CID_CONTRAST:
-               if ((ctrl->value = em28xx_contrast_get(dev)) < 0)
-                       return -EIO;
-               return 0;
-       case V4L2_CID_SATURATION:
-               if ((ctrl->value = em28xx_saturation_get(dev)) < 0)
-                       return -EIO;
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((tmp = em28xx_v_balance_get(dev)) < 0)
-                       return -EIO;
-               ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((tmp = em28xx_u_balance_get(dev)) < 0)
-                       return -EIO;
-               ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
-               return 0;
-       case V4L2_CID_GAMMA:
-               if ((ctrl->value = em28xx_gamma_get(dev)) < 0)
-                       return -EIO;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
 /*
  * em28xx_set_ctrl()
  * mute or set new saturation, brightness or contrast
@@ -761,27 +679,6 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
        }
 }
 
-/*FIXME: should be moved to saa711x */
-static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               return em28xx_brightness_set(dev, ctrl->value);
-       case V4L2_CID_CONTRAST:
-               return em28xx_contrast_set(dev, ctrl->value);
-       case V4L2_CID_SATURATION:
-               return em28xx_saturation_set(dev, ctrl->value);
-       case V4L2_CID_RED_BALANCE:
-               return em28xx_v_balance_set(dev, ctrl->value);
-       case V4L2_CID_BLUE_BALANCE:
-               return em28xx_u_balance_set(dev, ctrl->value);
-       case V4L2_CID_GAMMA:
-               return em28xx_gamma_set(dev, ctrl->value);
-       default:
-               return -EINVAL;
-       }
-}
-
 /*
  * em28xx_stream_interrupt()
  * stops streaming
@@ -802,7 +699,8 @@ static int em28xx_stream_interrupt(struct em28xx *dev)
        else if (ret) {
                dev->state |= DEV_MISCONFIGURED;
                em28xx_videodbg("device is misconfigured; close and "
-                       "open /dev/video%d again\n", dev->vdev->minor);
+                       "open /dev/video%d again\n",
+                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
                return ret;
        }
 
@@ -853,6 +751,181 @@ static int em28xx_set_norm(struct em28xx *dev, int width, int height)
        return 0;
 }
 
+static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format)
+{
+       em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
+               (format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
+               "V4L2_BUF_TYPE_VIDEO_CAPTURE" :
+               (format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ?
+               "V4L2_BUF_TYPE_VBI_CAPTURE" :
+               (format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ?
+               "V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " :
+               "not supported");
+
+       switch (format->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       {
+               format->fmt.pix.width = dev->width;
+               format->fmt.pix.height = dev->height;
+               format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+               format->fmt.pix.bytesperline = dev->bytesperline;
+               format->fmt.pix.sizeimage = dev->frame_size;
+               format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+               format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;       /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+
+               em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
+                       dev->height);
+               break;
+       }
+
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       {
+               format->fmt.sliced.service_set=0;
+
+               em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+
+               if (format->fmt.sliced.service_set==0)
+                       return -EINVAL;
+
+               break;
+       }
+
+       default:
+               return -EINVAL;
+       }
+       return (0);
+}
+
+static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format)
+{
+       u32 i;
+       int ret = 0;
+       int width = format->fmt.pix.width;
+       int height = format->fmt.pix.height;
+       unsigned int hscale, vscale;
+       unsigned int maxh, maxw;
+
+       maxw = norm_maxw(dev);
+       maxh = norm_maxh(dev);
+
+       em28xx_videodbg("%s: type=%s\n",
+                       cmd == VIDIOC_TRY_FMT ?
+                       "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
+                       format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+                       "V4L2_BUF_TYPE_VIDEO_CAPTURE" :
+                       format->type == V4L2_BUF_TYPE_VBI_CAPTURE ?
+                       "V4L2_BUF_TYPE_VBI_CAPTURE " :
+                       "not supported");
+
+       if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+               em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+
+               if (format->fmt.sliced.service_set==0)
+                       return -EINVAL;
+
+               return 0;
+       }
+
+
+       if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       em28xx_videodbg("%s: requested %dx%d\n",
+               cmd == VIDIOC_TRY_FMT ?
+               "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT",
+               format->fmt.pix.width, format->fmt.pix.height);
+
+       /* FIXME: Move some code away from here */
+       /* width must even because of the YUYV format */
+       /* height must be even because of interlacing */
+       height &= 0xfffe;
+       width &= 0xfffe;
+
+       if (height < 32)
+               height = 32;
+       if (height > maxh)
+               height = maxh;
+       if (width < 48)
+               width = 48;
+       if (width > maxw)
+               width = maxw;
+
+       if(dev->is_em2800){
+               /* the em2800 can only scale down to 50% */
+               if(height % (maxh / 2))
+                       height=maxh;
+               if(width % (maxw / 2))
+                       width=maxw;
+               /* according to empiatech support */
+               /* the MaxPacketSize is to small to support */
+               /* framesizes larger than 640x480 @ 30 fps */
+               /* or 640x576 @ 25 fps. As this would cut */
+               /* of a part of the image we prefer */
+               /* 360x576 or 360x480 for now */
+               if(width == maxw && height == maxh)
+                       width /= 2;
+       }
+
+       if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+               hscale = 0x3fff;
+
+       width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+       if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+               vscale = 0x3fff;
+
+       height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+       format->fmt.pix.width = width;
+       format->fmt.pix.height = height;
+       format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+       format->fmt.pix.bytesperline = width * 2;
+       format->fmt.pix.sizeimage = width * 2 * height;
+       format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+       em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
+               cmd == VIDIOC_TRY_FMT ?
+               "VIDIOC_TRY_FMT" :"VIDIOC_S_FMT",
+               format->fmt.pix.width, format->fmt.pix.height, hscale, vscale);
+
+       if (cmd == VIDIOC_TRY_FMT)
+               return 0;
+
+       for (i = 0; i < dev->num_frames; i++)
+               if (dev->frame[i].vma_use_count) {
+                       em28xx_videodbg("VIDIOC_S_FMT failed. "
+                               "Unmap the buffers first.\n");
+                       return -EINVAL;
+               }
+
+       /* stop io in case it is already in progress */
+       if (dev->stream == STREAM_ON) {
+               em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
+               if ((ret = em28xx_stream_interrupt(dev)))
+                       return ret;
+       }
+
+       em28xx_release_buffers(dev);
+       dev->io = IO_NONE;
+
+       /* set new image size */
+       dev->width = width;
+       dev->height = height;
+       dev->frame_size = dev->width * dev->height * 2;
+       dev->field_size = dev->frame_size >> 1;
+       dev->bytesperline = dev->width * 2;
+       dev->hscale = hscale;
+       dev->vscale = vscale;
+       em28xx_uninit_isoc(dev);
+       em28xx_set_alternate(dev);
+       em28xx_capture_start(dev, 1);
+       em28xx_resolution_set(dev);
+       em28xx_init_isoc(dev);
+
+       return 0;
+}
+
 /*
  * em28xx_v4l2_do_ioctl()
  * This function is _not_ called directly, but from
@@ -868,392 +941,325 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
        switch (cmd) {
                /* ---------- tv norms ---------- */
        case VIDIOC_ENUMSTD:
-               {
-                       struct v4l2_standard *e = arg;
-                       unsigned int i;
+       {
+               struct v4l2_standard *e = arg;
+               unsigned int i;
 
-                       i = e->index;
-                       if (i >= TVNORMS)
-                               return -EINVAL;
-                       ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
-                                                      tvnorms[e->index].name);
-                       e->index = i;
-                       if (ret < 0)
-                               return ret;
-                       return 0;
-               }
+               i = e->index;
+               if (i >= TVNORMS)
+                       return -EINVAL;
+               ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+                                               tvnorms[e->index].name);
+               e->index = i;
+               if (ret < 0)
+                       return ret;
+               return 0;
+       }
        case VIDIOC_G_STD:
-               {
-                       v4l2_std_id *id = arg;
+       {
+               v4l2_std_id *id = arg;
 
-                       *id = dev->tvnorm->id;
-                       return 0;
-               }
+               *id = dev->tvnorm->id;
+               return 0;
+       }
        case VIDIOC_S_STD:
-               {
-                       v4l2_std_id *id = arg;
-                       unsigned int i;
+       {
+               v4l2_std_id *id = arg;
+               unsigned int i;
 
+               for (i = 0; i < TVNORMS; i++)
+                       if (*id == tvnorms[i].id)
+                               break;
+               if (i == TVNORMS)
                        for (i = 0; i < TVNORMS; i++)
-                               if (*id == tvnorms[i].id)
+                               if (*id & tvnorms[i].id)
                                        break;
-                       if (i == TVNORMS)
-                               for (i = 0; i < TVNORMS; i++)
-                                       if (*id & tvnorms[i].id)
-                                               break;
-                       if (i == TVNORMS)
-                               return -EINVAL;
-
-                       down(&dev->lock);
-                       dev->tvnorm = &tvnorms[i];
+               if (i == TVNORMS)
+                       return -EINVAL;
 
-                       em28xx_set_norm(dev, dev->width, dev->height);
+               mutex_lock(&dev->lock);
+               dev->tvnorm = &tvnorms[i];
 
-/*
-               dev->width=norm_maxw(dev);
-               dev->height=norm_maxh(dev);
-               dev->frame_size=dev->width*dev->height*2;
-               dev->field_size=dev->frame_size>>1;
-               dev->bytesperline=dev->width*2;
-               dev->hscale=0;
-               dev->vscale=0;
+               em28xx_set_norm(dev, dev->width, dev->height);
 
-               em28xx_resolution_set(dev);
-*/
-/*
-               em28xx_uninit_isoc(dev);
-               em28xx_set_alternate(dev);
-               em28xx_capture_start(dev, 1);
-               em28xx_resolution_set(dev);
-               em28xx_init_isoc(dev);
-*/
-                       em28xx_i2c_call_clients(dev, DECODER_SET_NORM,
-                                               &tvnorms[i].mode);
-                       em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
-                                               &dev->tvnorm->id);
+               em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
+                                       &dev->tvnorm->id);
 
-                       up(&dev->lock);
+               mutex_unlock(&dev->lock);
 
-                       return 0;
-               }
+               return 0;
+       }
 
-               /* ------ input switching ---------- */
+       /* ------ input switching ---------- */
        case VIDIOC_ENUMINPUT:
-               {
-                       struct v4l2_input *i = arg;
-                       unsigned int n;
-                       static const char *iname[] = {
-                               [EM28XX_VMUX_COMPOSITE1] = "Composite1",
-                               [EM28XX_VMUX_COMPOSITE2] = "Composite2",
-                               [EM28XX_VMUX_COMPOSITE3] = "Composite3",
-                               [EM28XX_VMUX_COMPOSITE4] = "Composite4",
-                               [EM28XX_VMUX_SVIDEO] = "S-Video",
-                               [EM28XX_VMUX_TELEVISION] = "Television",
-                               [EM28XX_VMUX_CABLE] = "Cable TV",
-                               [EM28XX_VMUX_DVB] = "DVB",
-                               [EM28XX_VMUX_DEBUG] = "for debug only",
-                       };
-
-                       n = i->index;
-                       if (n >= MAX_EM28XX_INPUT)
-                               return -EINVAL;
-                       if (0 == INPUT(n)->type)
-                               return -EINVAL;
-                       memset(i, 0, sizeof(*i));
-                       i->index = n;
-                       i->type = V4L2_INPUT_TYPE_CAMERA;
-                       strcpy(i->name, iname[INPUT(n)->type]);
-                       if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
-                           (EM28XX_VMUX_CABLE == INPUT(n)->type))
-                               i->type = V4L2_INPUT_TYPE_TUNER;
-                       for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
-                               i->std |= tvnorms[n].id;
-                       return 0;
-               }
-
+       {
+               struct v4l2_input *i = arg;
+               unsigned int n;
+               static const char *iname[] = {
+                       [EM28XX_VMUX_COMPOSITE1] = "Composite1",
+                       [EM28XX_VMUX_COMPOSITE2] = "Composite2",
+                       [EM28XX_VMUX_COMPOSITE3] = "Composite3",
+                       [EM28XX_VMUX_COMPOSITE4] = "Composite4",
+                       [EM28XX_VMUX_SVIDEO] = "S-Video",
+                       [EM28XX_VMUX_TELEVISION] = "Television",
+                       [EM28XX_VMUX_CABLE] = "Cable TV",
+                       [EM28XX_VMUX_DVB] = "DVB",
+                       [EM28XX_VMUX_DEBUG] = "for debug only",
+               };
+
+               n = i->index;
+               if (n >= MAX_EM28XX_INPUT)
+                       return -EINVAL;
+               if (0 == INPUT(n)->type)
+                       return -EINVAL;
+               memset(i, 0, sizeof(*i));
+               i->index = n;
+               i->type = V4L2_INPUT_TYPE_CAMERA;
+               strcpy(i->name, iname[INPUT(n)->type]);
+               if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+                       (EM28XX_VMUX_CABLE == INPUT(n)->type))
+                       i->type = V4L2_INPUT_TYPE_TUNER;
+               for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
+                       i->std |= tvnorms[n].id;
+               return 0;
+       }
        case VIDIOC_G_INPUT:
-               {
-                       int *i = arg;
-                       *i = dev->ctl_input;
-
-                       return 0;
-               }
+       {
+               int *i = arg;
+               *i = dev->ctl_input;
 
+               return 0;
+       }
        case VIDIOC_S_INPUT:
-               {
-                       int *index = arg;
-
-                       if (*index >= MAX_EM28XX_INPUT)
-                               return -EINVAL;
-                       if (0 == INPUT(*index)->type)
-                               return -EINVAL;
+       {
+               int *index = arg;
 
-                       down(&dev->lock);
-                       video_mux(dev, *index);
-                       up(&dev->lock);
+               if (*index >= MAX_EM28XX_INPUT)
+                       return -EINVAL;
+               if (0 == INPUT(*index)->type)
+                       return -EINVAL;
 
-                       return 0;
-               }
+               mutex_lock(&dev->lock);
+               video_mux(dev, *index);
+               mutex_unlock(&dev->lock);
 
+               return 0;
+       }
        case VIDIOC_G_AUDIO:
-               {
-                       struct v4l2_audio *a = arg;
-                       unsigned int index = a->index;
+       {
+               struct v4l2_audio *a = arg;
+               unsigned int index = a->index;
 
-                       if (a->index > 1)
-                               return -EINVAL;
-                       memset(a, 0, sizeof(*a));
-                       index = dev->ctl_ainput;
+               if (a->index > 1)
+                       return -EINVAL;
+               memset(a, 0, sizeof(*a));
+               index = dev->ctl_ainput;
 
-                       if (index == 0) {
-                               strcpy(a->name, "Television");
-                       } else {
-                               strcpy(a->name, "Line In");
-                       }
-                       a->capability = V4L2_AUDCAP_STEREO;
-                       a->index = index;
-                       return 0;
+               if (index == 0) {
+                       strcpy(a->name, "Television");
+               } else {
+                       strcpy(a->name, "Line In");
                }
-
+               a->capability = V4L2_AUDCAP_STEREO;
+               a->index = index;
+               return 0;
+       }
        case VIDIOC_S_AUDIO:
-               {
-                       struct v4l2_audio *a = arg;
-                       if (a->index != dev->ctl_ainput)
-                               return -EINVAL;
+       {
+               struct v4l2_audio *a = arg;
 
-                       return 0;
-               }
+               if (a->index != dev->ctl_ainput)
+                       return -EINVAL;
 
-               /* --- controls ---------------------------------------------- */
+               return 0;
+       }
+
+       /* --- controls ---------------------------------------------- */
        case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *qc = arg;
-                       int i, id=qc->id;
-
-                       memset(qc,0,sizeof(*qc));
-                       qc->id=id;
-
-                       if (!dev->has_msp34xx) {
-                               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                                       if (qc->id && qc->id == em28xx_qctrl[i].id) {
-                                               memcpy(qc, &(em28xx_qctrl[i]),
-                                               sizeof(*qc));
-                                               return 0;
-                                       }
-                               }
-                       }
-                       if (dev->decoder == EM28XX_TVP5150) {
-                               em28xx_i2c_call_clients(dev,cmd,qc);
-                               if (qc->type)
-                                       return 0;
-                               else
-                                       return -EINVAL;
-                       }
-                       for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
-                               if (qc->id && qc->id == saa711x_qctrl[i].id) {
-                                       memcpy(qc, &(saa711x_qctrl[i]),
-                                              sizeof(*qc));
-                                       return 0;
-                               }
-                       }
+       {
+               struct v4l2_queryctrl *qc = arg;
+               int i, id=qc->id;
 
-                       return -EINVAL;
-               }
+               memset(qc,0,sizeof(*qc));
+               qc->id=id;
 
-       case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-                       int retval=-EINVAL;
-
-                       if (!dev->has_msp34xx)
-                               retval=em28xx_get_ctrl(dev, ctrl);
-                       if (retval==-EINVAL) {
-                               if (dev->decoder == EM28XX_TVP5150) {
-                                       em28xx_i2c_call_clients(dev,cmd,arg);
+               if (!dev->has_msp34xx) {
+                       for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+                               if (qc->id && qc->id == em28xx_qctrl[i].id) {
+                                       memcpy(qc, &(em28xx_qctrl[i]),
+                                       sizeof(*qc));
                                        return 0;
                                }
-
-                               return saa711x_get_ctrl(dev, ctrl);
-                       } else return retval;
+                       }
                }
+               em28xx_i2c_call_clients(dev,cmd,qc);
+               if (qc->type)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+               int retval=-EINVAL;
 
+               if (!dev->has_msp34xx)
+                       retval=em28xx_get_ctrl(dev, ctrl);
+               if (retval==-EINVAL) {
+                       em28xx_i2c_call_clients(dev,cmd,arg);
+                       return 0;
+               } else return retval;
+       }
        case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-                       u8 i;
-
-                       if (!dev->has_msp34xx){
-                               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                                       if (ctrl->id == em28xx_qctrl[i].id) {
-                                               if (ctrl->value <
-                                               em28xx_qctrl[i].minimum
-                                               || ctrl->value >
-                                               em28xx_qctrl[i].maximum)
-                                                       return -ERANGE;
-                                               return em28xx_set_ctrl(dev, ctrl);
-                                       }
-                               }
-                       }
-
-                       if (dev->decoder == EM28XX_TVP5150) {
-                               em28xx_i2c_call_clients(dev,cmd,arg);
-                               return 0;
-                       } else if (!dev->has_msp34xx) {
-                               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                                       if (ctrl->id == em28xx_qctrl[i].id) {
-                                               if (ctrl->value <
-                                               em28xx_qctrl[i].minimum
-                                               || ctrl->value >
-                                               em28xx_qctrl[i].maximum)
-                                                       return -ERANGE;
-                                               return em28xx_set_ctrl(dev, ctrl);
-                                       }
-                               }
-                               for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
-                                       if (ctrl->id == saa711x_qctrl[i].id) {
-                                               if (ctrl->value <
-                                               saa711x_qctrl[i].minimum
-                                               || ctrl->value >
-                                               saa711x_qctrl[i].maximum)
-                                                       return -ERANGE;
-                                               return saa711x_set_ctrl(dev, ctrl);
-                                       }
+       {
+               struct v4l2_control *ctrl = arg;
+               u8 i;
+
+               if (!dev->has_msp34xx){
+                       for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
+                               if (ctrl->id == em28xx_qctrl[i].id) {
+                                       if (ctrl->value <
+                                       em28xx_qctrl[i].minimum
+                                       || ctrl->value >
+                                       em28xx_qctrl[i].maximum)
+                                               return -ERANGE;
+                                       return em28xx_set_ctrl(dev, ctrl);
                                }
                        }
-
-                       return -EINVAL;
                }
 
-               /* --- tuner ioctls ------------------------------------------ */
+               em28xx_i2c_call_clients(dev,cmd,arg);
+               return 0;
+       }
+       /* --- tuner ioctls ------------------------------------------ */
        case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *t = arg;
-                       int status = 0;
+       {
+               struct v4l2_tuner *t = arg;
+               int status = 0;
 
-                       if (0 != t->index)
-                               return -EINVAL;
+               if (0 != t->index)
+                       return -EINVAL;
 
-                       memset(t, 0, sizeof(*t));
-                       strcpy(t->name, "Tuner");
-                       t->type = V4L2_TUNER_ANALOG_TV;
-                       t->capability = V4L2_TUNER_CAP_NORM;
-                       t->rangehigh = 0xffffffffUL;    /* FIXME: set correct range */
+               memset(t, 0, sizeof(*t));
+               strcpy(t->name, "Tuner");
+               t->type = V4L2_TUNER_ANALOG_TV;
+               t->capability = V4L2_TUNER_CAP_NORM;
+               t->rangehigh = 0xffffffffUL;    /* FIXME: set correct range */
 /*             t->signal = 0xffff;*/
 /*             em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/
-                       /* No way to get signal strength? */
-                       down(&dev->lock);
-                       em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
-                                               &status);
-                       up(&dev->lock);
-                       t->signal =
-                           (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
-
-                       em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
-                                t->afc);
-                       return 0;
-               }
+               /* No way to get signal strength? */
+               mutex_lock(&dev->lock);
+               em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+                                       &status);
+               mutex_unlock(&dev->lock);
+               t->signal =
+                       (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+               em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
+                               t->afc);
+               return 0;
+       }
        case VIDIOC_S_TUNER:
-               {
-                       struct v4l2_tuner *t = arg;
-                       int status = 0;
+       {
+               struct v4l2_tuner *t = arg;
+               int status = 0;
 
-                       if (0 != t->index)
-                               return -EINVAL;
-                       memset(t, 0, sizeof(*t));
-                       strcpy(t->name, "Tuner");
-                       t->type = V4L2_TUNER_ANALOG_TV;
-                       t->capability = V4L2_TUNER_CAP_NORM;
-                       t->rangehigh = 0xffffffffUL;    /* FIXME: set correct range */
+               if (0 != t->index)
+                       return -EINVAL;
+               memset(t, 0, sizeof(*t));
+               strcpy(t->name, "Tuner");
+               t->type = V4L2_TUNER_ANALOG_TV;
+               t->capability = V4L2_TUNER_CAP_NORM;
+               t->rangehigh = 0xffffffffUL;    /* FIXME: set correct range */
 /*             t->signal = 0xffff; */
-                       /* No way to get signal strength? */
-                       down(&dev->lock);
-                       em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
-                                               &status);
-                       up(&dev->lock);
-                       t->signal =
-                           (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
-
-                       em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
-                                t->signal, t->afc);
-                       return 0;
-               }
+               /* No way to get signal strength? */
+               mutex_lock(&dev->lock);
+               em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+                                       &status);
+               mutex_unlock(&dev->lock);
+               t->signal =
+                       (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+               em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
+                               t->signal, t->afc);
+               return 0;
+       }
        case VIDIOC_G_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
+       {
+               struct v4l2_frequency *f = arg;
 
-                       memset(f, 0, sizeof(*f));
-                       f->type = V4L2_TUNER_ANALOG_TV;
-                       f->frequency = dev->ctl_freq;
+               memset(f, 0, sizeof(*f));
+               f->type = V4L2_TUNER_ANALOG_TV;
+               f->frequency = dev->ctl_freq;
 
-                       return 0;
-               }
+               return 0;
+       }
        case VIDIOC_S_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
-
-                       if (0 != f->tuner)
-                               return -EINVAL;
+       {
+               struct v4l2_frequency *f = arg;
 
-                       if (V4L2_TUNER_ANALOG_TV != f->type)
-                               return -EINVAL;
+               if (0 != f->tuner)
+                       return -EINVAL;
 
-                       down(&dev->lock);
-                       dev->ctl_freq = f->frequency;
-                       em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
-                       up(&dev->lock);
-                       return 0;
-               }
+               if (V4L2_TUNER_ANALOG_TV != f->type)
+                       return -EINVAL;
 
+               mutex_lock(&dev->lock);
+               dev->ctl_freq = f->frequency;
+               em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+               mutex_unlock(&dev->lock);
+               return 0;
+       }
        case VIDIOC_CROPCAP:
-               {
-                       struct v4l2_cropcap *cc = arg;
+       {
+               struct v4l2_cropcap *cc = arg;
 
-                       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-                       cc->bounds.left = 0;
-                       cc->bounds.top = 0;
-                       cc->bounds.width = dev->width;
-                       cc->bounds.height = dev->height;
-                       cc->defrect = cc->bounds;
-                       cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
-                       cc->pixelaspect.denominator = 59;
-                       return 0;
-               }
+               if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       return -EINVAL;
+               cc->bounds.left = 0;
+               cc->bounds.top = 0;
+               cc->bounds.width = dev->width;
+               cc->bounds.height = dev->height;
+               cc->defrect = cc->bounds;
+               cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+               cc->pixelaspect.denominator = 59;
+               return 0;
+       }
        case VIDIOC_STREAMON:
-               {
-                       int *type = arg;
+       {
+               int *type = arg;
 
-                       if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-                           || dev->io != IO_MMAP)
-                               return -EINVAL;
+               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+                       || dev->io != IO_MMAP)
+                       return -EINVAL;
 
-                       if (list_empty(&dev->inqueue))
-                               return -EINVAL;
+               if (list_empty(&dev->inqueue))
+                       return -EINVAL;
 
-                       dev->stream = STREAM_ON;        /* FIXME: Start video capture here? */
+               dev->stream = STREAM_ON;        /* FIXME: Start video capture here? */
 
-                       em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+               em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
 
-                       return 0;
-               }
+               return 0;
+       }
        case VIDIOC_STREAMOFF:
-               {
-                       int *type = arg;
-                       int ret;
-
-                       if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-                           || dev->io != IO_MMAP)
-                               return -EINVAL;
+       {
+               int *type = arg;
+               int ret;
 
-                       if (dev->stream == STREAM_ON) {
-                               em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
-                               if ((ret = em28xx_stream_interrupt(dev)))
-                                       return ret;
-                       }
-                       em28xx_empty_framequeues(dev);
+               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+                       || dev->io != IO_MMAP)
+                       return -EINVAL;
 
-                       return 0;
+               if (dev->stream == STREAM_ON) {
+                       em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
+                       if ((ret = em28xx_stream_interrupt(dev)))
+                               return ret;
                }
+               em28xx_empty_framequeues(dev);
+
+               return 0;
+       }
        default:
                return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
                                                  driver_ioctl);
@@ -1283,327 +1289,170 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
                /* --- capabilities ------------------------------------------ */
        case VIDIOC_QUERYCAP:
                {
-                       struct v4l2_capability *cap = arg;
-
-                       memset(cap, 0, sizeof(*cap));
-                       strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
-                       strlcpy(cap->card, em28xx_boards[dev->model].name,
-                               sizeof(cap->card));
-                       strlcpy(cap->bus_info, dev->udev->dev.bus_id,
-                               sizeof(cap->bus_info));
-                       cap->version = EM28XX_VERSION_CODE;
-                       cap->capabilities =
-                           V4L2_CAP_VIDEO_CAPTURE |
-                           V4L2_CAP_AUDIO |
-                           V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-                       if (dev->has_tuner)
-                               cap->capabilities |= V4L2_CAP_TUNER;
-                       return 0;
-               }
-
-               /* --- capture ioctls ---------------------------------------- */
+               struct v4l2_capability *cap = arg;
+
+               memset(cap, 0, sizeof(*cap));
+               strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+               strlcpy(cap->card, em28xx_boards[dev->model].name,
+                       sizeof(cap->card));
+               strlcpy(cap->bus_info, dev->udev->dev.bus_id,
+                       sizeof(cap->bus_info));
+               cap->version = EM28XX_VERSION_CODE;
+               cap->capabilities =
+                               V4L2_CAP_SLICED_VBI_CAPTURE |
+                               V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_AUDIO |
+                               V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+               if (dev->has_tuner)
+                       cap->capabilities |= V4L2_CAP_TUNER;
+               return 0;
+       }
+       /* --- capture ioctls ---------------------------------------- */
        case VIDIOC_ENUM_FMT:
-               {
-                       struct v4l2_fmtdesc *fmtd = arg;
-
-                       if (fmtd->index != 0)
-                               return -EINVAL;
-                       memset(fmtd, 0, sizeof(*fmtd));
-                       fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       strcpy(fmtd->description, "Packed YUY2");
-                       fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
-                       memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
-                       return 0;
-               }
+       {
+               struct v4l2_fmtdesc *fmtd = arg;
 
+               if (fmtd->index != 0)
+                       return -EINVAL;
+               memset(fmtd, 0, sizeof(*fmtd));
+               fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               strcpy(fmtd->description, "Packed YUY2");
+               fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+               memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+               return 0;
+       }
        case VIDIOC_G_FMT:
-               {
-                       struct v4l2_format *format = arg;
-
-                       em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
-                                format->type ==
-                                V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-                                "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
-                                V4L2_BUF_TYPE_VBI_CAPTURE ?
-                                "V4L2_BUF_TYPE_VBI_CAPTURE " :
-                                "not supported");
-
-                       if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-
-                       format->fmt.pix.width = dev->width;
-                       format->fmt.pix.height = dev->height;
-                       format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-                       format->fmt.pix.bytesperline = dev->bytesperline;
-                       format->fmt.pix.sizeimage = dev->frame_size;
-                       format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-                       format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;       /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
-
-                       em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
-                                dev->height);
-                       return 0;
-               }
+               return em28xx_get_fmt(dev, (struct v4l2_format *) arg);
 
        case VIDIOC_TRY_FMT:
        case VIDIOC_S_FMT:
-               {
-                       struct v4l2_format *format = arg;
-                       u32 i;
-                       int ret = 0;
-                       int width = format->fmt.pix.width;
-                       int height = format->fmt.pix.height;
-                       unsigned int hscale, vscale;
-                       unsigned int maxh, maxw;
-
-                       maxw = norm_maxw(dev);
-                       maxh = norm_maxh(dev);
-
-/*             int both_fields; */
-
-                       em28xx_videodbg("%s: type=%s\n",
-                                cmd ==
-                                VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
-                                "VIDIOC_S_FMT",
-                                format->type ==
-                                V4L2_BUF_TYPE_VIDEO_CAPTURE ?
-                                "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
-                                V4L2_BUF_TYPE_VBI_CAPTURE ?
-                                "V4L2_BUF_TYPE_VBI_CAPTURE " :
-                                "not supported");
-
-                       if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-
-                       em28xx_videodbg("%s: requested %dx%d\n",
-                                cmd ==
-                                VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
-                                "VIDIOC_S_FMT", format->fmt.pix.width,
-                                format->fmt.pix.height);
-
-                       /* FIXME: Move some code away from here */
-                       /* width must even because of the YUYV format */
-                       /* height must be even because of interlacing */
-                       height &= 0xfffe;
-                       width &= 0xfffe;
-
-                       if (height < 32)
-                               height = 32;
-                       if (height > maxh)
-                               height = maxh;
-                       if (width < 48)
-                               width = 48;
-                       if (width > maxw)
-                               width = maxw;
-
-                       if(dev->is_em2800){
-                               /* the em2800 can only scale down to 50% */
-                               if(height % (maxh / 2))
-                                       height=maxh;
-                               if(width % (maxw / 2))
-                                       width=maxw;
-                               /* according to empiatech support */
-                               /* the MaxPacketSize is to small to support */
-                               /* framesizes larger than 640x480 @ 30 fps */
-                               /* or 640x576 @ 25 fps. As this would cut */
-                               /* of a part of the image we prefer */
-                               /* 360x576 or 360x480 for now */
-                               if(width == maxw && height == maxh)
-                                       width /= 2;
-                       }
-
-                       if ((hscale =
-                            (((unsigned long)maxw) << 12) / width - 4096L) >=
-                           0x4000)
-                               hscale = 0x3fff;
-                       width =
-                           (((unsigned long)maxw) << 12) / (hscale + 4096L);
-
-                       if ((vscale =
-                            (((unsigned long)maxh) << 12) / height - 4096L) >=
-                           0x4000)
-                               vscale = 0x3fff;
-                       height =
-                           (((unsigned long)maxh) << 12) / (vscale + 4096L);
-
-                       format->fmt.pix.width = width;
-                       format->fmt.pix.height = height;
-                       format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-                       format->fmt.pix.bytesperline = width * 2;
-                       format->fmt.pix.sizeimage = width * 2 * height;
-                       format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-                       format->fmt.pix.field = V4L2_FIELD_INTERLACED;
-
-                       em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
-                                cmd ==
-                                VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
-                                "VIDIOC_S_FMT", format->fmt.pix.width,
-                                format->fmt.pix.height, hscale, vscale);
-
-                       if (cmd == VIDIOC_TRY_FMT)
-                               return 0;
-
-                       for (i = 0; i < dev->num_frames; i++)
-                               if (dev->frame[i].vma_use_count) {
-                                       em28xx_videodbg("VIDIOC_S_FMT failed. "
-                                               "Unmap the buffers first.\n");
-                                       return -EINVAL;
-                               }
+               return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
 
-                       /* stop io in case it is already in progress */
-                       if (dev->stream == STREAM_ON) {
-                               em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
-                               if ((ret = em28xx_stream_interrupt(dev)))
-                                       return ret;
-                       }
+       case VIDIOC_REQBUFS:
+       {
+               struct v4l2_requestbuffers *rb = arg;
+               u32 i;
+               int ret;
 
-                       em28xx_release_buffers(dev);
-                       dev->io = IO_NONE;
-
-                       /* set new image size */
-                       dev->width = width;
-                       dev->height = height;
-                       dev->frame_size = dev->width * dev->height * 2;
-                       dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
-                       dev->bytesperline = dev->width * 2;
-                       dev->hscale = hscale;
-                       dev->vscale = vscale;
-/*                     dev->both_fileds = both_fileds; */
-                       em28xx_uninit_isoc(dev);
-                       em28xx_set_alternate(dev);
-                       em28xx_capture_start(dev, 1);
-                       em28xx_resolution_set(dev);
-                       em28xx_init_isoc(dev);
+               if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                       rb->memory != V4L2_MEMORY_MMAP)
+                       return -EINVAL;
 
-                       return 0;
+               if (dev->io == IO_READ) {
+                       em28xx_videodbg ("method is set to read;"
+                               " close and open the device again to"
+                               " choose the mmap I/O method\n");
+                       return -EINVAL;
                }
 
-               /* --- streaming capture ------------------------------------- */
-       case VIDIOC_REQBUFS:
-               {
-                       struct v4l2_requestbuffers *rb = arg;
-                       u32 i;
-                       int ret;
-
-                       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                           rb->memory != V4L2_MEMORY_MMAP)
-                               return -EINVAL;
-
-                       if (dev->io == IO_READ) {
-                               em28xx_videodbg ("method is set to read;"
-                                       " close and open the device again to"
-                                       " choose the mmap I/O method\n");
+               for (i = 0; i < dev->num_frames; i++)
+                       if (dev->frame[i].vma_use_count) {
+                               em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
                                return -EINVAL;
                        }
 
-                       for (i = 0; i < dev->num_frames; i++)
-                               if (dev->frame[i].vma_use_count) {
-                                       em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
-                                       return -EINVAL;
-                               }
-
-                       if (dev->stream == STREAM_ON) {
-                               em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
-                               if ((ret = em28xx_stream_interrupt(dev)))
-                                       return ret;
-                       }
-
-                       em28xx_empty_framequeues(dev);
+               if (dev->stream == STREAM_ON) {
+                       em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+                       if ((ret = em28xx_stream_interrupt(dev)))
+                               return ret;
+               }
 
-                       em28xx_release_buffers(dev);
-                       if (rb->count)
-                               rb->count =
-                                   em28xx_request_buffers(dev, rb->count);
+               em28xx_empty_framequeues(dev);
 
-                       dev->frame_current = NULL;
+               em28xx_release_buffers(dev);
+               if (rb->count)
+                       rb->count =
+                               em28xx_request_buffers(dev, rb->count);
 
-                       em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
-                                                    rb->count);
-                       dev->io = rb->count ? IO_MMAP : IO_NONE;
-                       return 0;
-               }
+               dev->frame_current = NULL;
 
+               em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
+                                               rb->count);
+               dev->io = rb->count ? IO_MMAP : IO_NONE;
+               return 0;
+       }
        case VIDIOC_QUERYBUF:
-               {
-                       struct v4l2_buffer *b = arg;
+       {
+               struct v4l2_buffer *b = arg;
 
-                       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                           b->index >= dev->num_frames || dev->io != IO_MMAP)
-                               return -EINVAL;
+               if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                       b->index >= dev->num_frames || dev->io != IO_MMAP)
+                       return -EINVAL;
 
-                       memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+               memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
 
-                       if (dev->frame[b->index].vma_use_count) {
-                               b->flags |= V4L2_BUF_FLAG_MAPPED;
-                       }
-                       if (dev->frame[b->index].state == F_DONE)
-                               b->flags |= V4L2_BUF_FLAG_DONE;
-                       else if (dev->frame[b->index].state != F_UNUSED)
-                               b->flags |= V4L2_BUF_FLAG_QUEUED;
-                       return 0;
+               if (dev->frame[b->index].vma_use_count) {
+                       b->flags |= V4L2_BUF_FLAG_MAPPED;
                }
+               if (dev->frame[b->index].state == F_DONE)
+                       b->flags |= V4L2_BUF_FLAG_DONE;
+               else if (dev->frame[b->index].state != F_UNUSED)
+                       b->flags |= V4L2_BUF_FLAG_QUEUED;
+               return 0;
+       }
        case VIDIOC_QBUF:
-               {
-                       struct v4l2_buffer *b = arg;
-                       unsigned long lock_flags;
+       {
+               struct v4l2_buffer *b = arg;
+               unsigned long lock_flags;
 
-                       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                           b->index >= dev->num_frames || dev->io != IO_MMAP) {
-                               return -EINVAL;
-                       }
+               if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                       b->index >= dev->num_frames || dev->io != IO_MMAP) {
+                       return -EINVAL;
+               }
 
-                       if (dev->frame[b->index].state != F_UNUSED) {
-                               return -EAGAIN;
-                       }
-                       dev->frame[b->index].state = F_QUEUED;
+               if (dev->frame[b->index].state != F_UNUSED) {
+                       return -EAGAIN;
+               }
+               dev->frame[b->index].state = F_QUEUED;
 
-                       /* add frame to fifo */
-                       spin_lock_irqsave(&dev->queue_lock, lock_flags);
-                       list_add_tail(&dev->frame[b->index].frame,
-                                     &dev->inqueue);
-                       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+               /* add frame to fifo */
+               spin_lock_irqsave(&dev->queue_lock, lock_flags);
+               list_add_tail(&dev->frame[b->index].frame,
+                               &dev->inqueue);
+               spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
 
-                       return 0;
-               }
+               return 0;
+       }
        case VIDIOC_DQBUF:
-               {
-                       struct v4l2_buffer *b = arg;
-                       struct em28xx_frame_t *f;
-                       unsigned long lock_flags;
-                       int ret = 0;
+       {
+               struct v4l2_buffer *b = arg;
+               struct em28xx_frame_t *f;
+               unsigned long lock_flags;
+               int ret = 0;
 
-                       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-                           || dev->io != IO_MMAP)
-                               return -EINVAL;
+               if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+                       || dev->io != IO_MMAP)
+                       return -EINVAL;
 
-                       if (list_empty(&dev->outqueue)) {
-                               if (dev->stream == STREAM_OFF)
-                                       return -EINVAL;
-                               if (filp->f_flags & O_NONBLOCK)
-                                       return -EAGAIN;
-                               ret = wait_event_interruptible
-                                   (dev->wait_frame,
-                                    (!list_empty(&dev->outqueue)) ||
-                                    (dev->state & DEV_DISCONNECTED));
-                               if (ret)
-                                       return ret;
-                               if (dev->state & DEV_DISCONNECTED)
-                                       return -ENODEV;
-                       }
+               if (list_empty(&dev->outqueue)) {
+                       if (dev->stream == STREAM_OFF)
+                               return -EINVAL;
+                       if (filp->f_flags & O_NONBLOCK)
+                               return -EAGAIN;
+                       ret = wait_event_interruptible
+                               (dev->wait_frame,
+                               (!list_empty(&dev->outqueue)) ||
+                               (dev->state & DEV_DISCONNECTED));
+                       if (ret)
+                               return ret;
+                       if (dev->state & DEV_DISCONNECTED)
+                               return -ENODEV;
+               }
 
-                       spin_lock_irqsave(&dev->queue_lock, lock_flags);
-                       f = list_entry(dev->outqueue.next,
-                                      struct em28xx_frame_t, frame);
-                       list_del(dev->outqueue.next);
-                       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+               spin_lock_irqsave(&dev->queue_lock, lock_flags);
+               f = list_entry(dev->outqueue.next,
+                               struct em28xx_frame_t, frame);
+               list_del(dev->outqueue.next);
+               spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
 
-                       f->state = F_UNUSED;
-                       memcpy(b, &f->buf, sizeof(*b));
+               f->state = F_UNUSED;
+               memcpy(b, &f->buf, sizeof(*b));
 
-                       if (f->vma_use_count)
-                               b->flags |= V4L2_BUF_FLAG_MAPPED;
+               if (f->vma_use_count)
+                       b->flags |= V4L2_BUF_FLAG_MAPPED;
 
-                       return 0;
-               }
+               return 0;
+       }
        default:
                return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
                                       em28xx_video_do_ioctl);
@@ -1621,25 +1470,25 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
        int ret = 0;
        struct em28xx *dev = filp->private_data;
 
-       if (down_interruptible(&dev->fileop_lock))
+       if (mutex_lock_interruptible(&dev->fileop_lock))
                return -ERESTARTSYS;
 
        if (dev->state & DEV_DISCONNECTED) {
                em28xx_errdev("v4l2 ioctl: device not present\n");
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -ENODEV;
        }
 
        if (dev->state & DEV_MISCONFIGURED) {
                em28xx_errdev
                    ("v4l2 ioctl: device is misconfigured; close and open it again\n");
-               up(&dev->fileop_lock);
+               mutex_unlock(&dev->fileop_lock);
                return -EIO;
        }
 
        ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
 
-       up(&dev->fileop_lock);
+       mutex_unlock(&dev->fileop_lock);
 
        return ret;
 }
@@ -1673,7 +1522,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 
        dev->udev = udev;
        dev->model = model;
-       init_MUTEX(&dev->lock);
+       mutex_init(&dev->lock);
        init_waitqueue_head(&dev->open);
 
        dev->em28xx_write_regs = em28xx_write_regs;
@@ -1729,10 +1578,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        dev->vpic.depth = 16;
        dev->vpic.palette = VIDEO_PALETTE_YUV422;
 
+       em28xx_pre_card_setup(dev);
 #ifdef CONFIG_MODULES
        /* request some modules */
        if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
-               request_module("saa711x");
+               request_module("saa7115");
        if (dev->decoder == EM28XX_TVP5150)
                request_module("tvp5150");
        if (dev->has_tuner)
@@ -1744,10 +1594,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        if (errCode) {
                em28xx_errdev("error configuring device\n");
                kfree(dev);
+               em28xx_devused&=~(1<<dev->devno);
                return -ENOMEM;
        }
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        /* register i2c bus */
        em28xx_i2c_register(dev);
 
@@ -1757,7 +1608,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        /* configure the device */
        em28xx_config_i2c(dev);
 
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 
        errCode = em28xx_config(dev);
 
@@ -1770,9 +1621,30 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        if (NULL == dev->vdev) {
                em28xx_errdev("cannot allocate video_device.\n");
                kfree(dev);
+               em28xx_devused&=~(1<<dev->devno);
                return -ENOMEM;
        }
 
+       dev->vbi_dev = video_device_alloc();
+       if (NULL == dev->vbi_dev) {
+               em28xx_errdev("cannot allocate video_device.\n");
+               kfree(dev->vdev);
+               kfree(dev);
+               em28xx_devused&=~(1<<dev->devno);
+               return -ENOMEM;
+       }
+
+       /* Fills VBI device info */
+       dev->vbi_dev->type = VFL_TYPE_VBI;
+       dev->vbi_dev->hardware = 0;
+       dev->vbi_dev->fops = &em28xx_v4l_fops;
+       dev->vbi_dev->minor = -1;
+       dev->vbi_dev->dev = &dev->udev->dev;
+       dev->vbi_dev->release = video_device_release;
+       snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
+                                                        "em28xx",dev->devno,"vbi");
+
+       /* Fills CAPTURE device info */
        dev->vdev->type = VID_TYPE_CAPTURE;
        if (dev->has_tuner)
                dev->vdev->type |= VID_TYPE_TUNER;
@@ -1781,21 +1653,39 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        dev->vdev->minor = -1;
        dev->vdev->dev = &dev->udev->dev;
        dev->vdev->release = video_device_release;
-       snprintf(dev->vdev->name, sizeof(dev->vdev->name), "%s",
-                "em28xx video");
+       snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s",
+                                                        "em28xx",dev->devno,"video");
+
        list_add_tail(&dev->devlist,&em28xx_devlist);
 
        /* register v4l2 device */
-       down(&dev->lock);
-       if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) {
+       mutex_lock(&dev->lock);
+       if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+                                        video_nr[dev->devno]))) {
                em28xx_errdev("unable to register video device (error=%i).\n",
                              retval);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                list_del(&dev->devlist);
                video_device_release(dev->vdev);
                kfree(dev);
+               em28xx_devused&=~(1<<dev->devno);
                return -ENODEV;
        }
+
+       if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+                                       vbi_nr[dev->devno]) < 0) {
+               printk("unable to register vbi device\n");
+               mutex_unlock(&dev->lock);
+               list_del(&dev->devlist);
+               video_device_release(dev->vbi_dev);
+               video_device_release(dev->vdev);
+               kfree(dev);
+               em28xx_devused&=~(1<<dev->devno);
+               return -ENODEV;
+       } else {
+               printk("registered VBI\n");
+       }
+
        if (dev->has_msp34xx) {
                /* Send a reset to other chips via gpio */
                em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
@@ -1806,10 +1696,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        }
        video_mux(dev, 0);
 
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 
-       em28xx_info("V4L2 device registered as /dev/video%d\n",
-                   dev->vdev->minor);
+       em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
+                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN,
+                               dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
 
        return 0;
 }
@@ -1831,6 +1722,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        udev = usb_get_dev(interface_to_usbdev(interface));
        ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 
+       /* Check to see next free device and mark as used */
+       nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS);
+       em28xx_devused|=1<<nr;
 
        /* Don't register audio interfaces */
        if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
@@ -1838,6 +1732,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                                udev->descriptor.idVendor,udev->descriptor.idProduct,
                                ifnum,
                                interface->altsetting[0].desc.bInterfaceClass);
+
+               em28xx_devused&=~(1<<nr);
                return -ENODEV;
        }
 
@@ -1852,18 +1748,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
            USB_ENDPOINT_XFER_ISOC) {
                em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
+               em28xx_devused&=~(1<<nr);
                return -ENODEV;
        }
        if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
                em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
+               em28xx_devused&=~(1<<nr);
                return -ENODEV;
        }
 
        model=id->driver_info;
-       nr=interface->minor;
 
-       if (nr>EM28XX_MAXBOARDS) {
+       if (nr >= EM28XX_MAXBOARDS) {
                printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
+               em28xx_devused&=~(1<<nr);
                return -ENOMEM;
        }
 
@@ -1871,19 +1769,24 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                em28xx_err(DRIVER_NAME ": out of memory!\n");
+               em28xx_devused&=~(1<<nr);
                return -ENOMEM;
        }
 
+       snprintf(dev->name, 29, "em28xx #%d", nr);
+       dev->devno=nr;
+
        /* compute alternate max packet sizes */
        uif = udev->actconfig->interface[0];
 
        dev->num_alt=uif->num_altsetting;
-       printk(DRIVER_NAME ": Alternate settings: %i\n",dev->num_alt);
+       em28xx_info("Alternate settings: %i\n",dev->num_alt);
 //     dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
        dev->alt_max_pkt_size = kmalloc(32*
                                                dev->num_alt,GFP_KERNEL);
        if (dev->alt_max_pkt_size == NULL) {
-               em28xx_err(DRIVER_NAME ": out of memory!\n");
+               em28xx_errdev("out of memory!\n");
+               em28xx_devused&=~(1<<nr);
                return -ENOMEM;
        }
 
@@ -1892,27 +1795,26 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                                                        wMaxPacketSize);
                dev->alt_max_pkt_size[i] =
                    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
-               printk(DRIVER_NAME ": Alternate setting %i, max size= %i\n",i,
+               em28xx_info("Alternate setting %i, max size= %i\n",i,
                                                        dev->alt_max_pkt_size[i]);
        }
 
-       snprintf(dev->name, 29, "em28xx #%d", nr);
-
        if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
                model=card[nr];
 
        if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
-               printk( "%s: Your board has no eeprom inside it and thus can't\n"
+               em28xx_errdev( "Your board has no eeprom inside it and thus can't\n"
                        "%s: be autodetected.  Please pass card=<n> insmod option to\n"
                        "%s: workaround that.  Redirect complaints to the vendor of\n"
-                       "%s: the TV card.  Best regards,\n"
+                       "%s: the TV card. Generic type will be used."
+                       "%s: Best regards,\n"
                        "%s:         -- tux\n",
                        dev->name,dev->name,dev->name,dev->name,dev->name);
-               printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+               em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
                        dev->name);
                for (i = 0; i < em28xx_bcount; i++) {
-                       printk("%s:    card=%d -> %s\n",
-                               dev->name, i, em28xx_boards[i].name);
+                       em28xx_errdev("    card=%d -> %s\n", i,
+                                                       em28xx_boards[i].name);
                }
        }
 
@@ -1938,15 +1840,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
        struct em28xx *dev = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
 
-/*FIXME: IR should be disconnected */
-
        if (!dev)
                return;
 
-
        down_write(&em28xx_disconnect);
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
 
        em28xx_info("disconnecting %s\n", dev->vdev->name);
 
@@ -1955,7 +1854,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
        if (dev->users) {
                em28xx_warn
                    ("device /dev/video%d is open! Deregistration and memory "
-                    "deallocation are deferred on close.\n", dev->vdev->minor);
+                    "deallocation are deferred on close.\n",
+                               dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
+
                dev->state |= DEV_MISCONFIGURED;
                em28xx_uninit_isoc(dev);
                dev->state |= DEV_DISCONNECTED;
@@ -1966,7 +1867,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                em28xx_release_resources(dev);
        }
 
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 
        if (!dev->users) {
                kfree(dev->alt_max_pkt_size);
index 33de9d8..e1ddc2f 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/videodev.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 #include <media/ir-kbd-i2c.h>
 
 /* Boards supported by driver */
 #define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
 #define EM2800_BOARD_KWORLD_USB2800             8
 #define EM2820_BOARD_PINNACLE_DVC_90           9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900   10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS                11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF                12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS       13
 
 #define UNSET -1
 
@@ -209,6 +214,7 @@ struct em28xx {
        /* generic device properties */
        char name[30];          /* name (including minor) of the device */
        int model;              /* index in the device_data struct */
+       int devno;              /* marks the number of this device */
        unsigned int is_em2800;
        int video_inputs;       /* number of video inputs */
        struct list_head        devlist;
@@ -256,7 +262,7 @@ struct em28xx {
        enum em28xx_stream_state stream;
        enum em28xx_io_method io;
        /* locks */
-       struct semaphore lock, fileop_lock;
+       struct mutex lock, fileop_lock;
        spinlock_t queue_lock;
        struct list_head inqueue, outqueue;
        wait_queue_head_t open, wait_frame, wait_stream;
@@ -326,6 +332,7 @@ int em28xx_set_alternate(struct em28xx *dev);
 
 /* Provided by em28xx-cards.c */
 extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern void em28xx_pre_card_setup(struct em28xx *dev);
 extern void em28xx_card_setup(struct em28xx *dev);
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
index e7bbeb1..c7fed34 100644 (file)
@@ -1,9 +1,9 @@
 /*
     hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
-               
+
     Visit http://www.mihu.de/linux/saa7146/ and follow the link
     to "hexium" for further details about this card.
-    
+
     Copyright (C) 2003 Michael Hunold <michael@mihu.de>
 
     This program is free software; you can redistribute it and/or modify
@@ -81,7 +81,7 @@ struct hexium
 
        struct video_device     *video_dev;
        struct i2c_adapter      i2c_adapter;
-               
+
        int             cur_input;      /* current input */
        v4l2_std_id     cur_std;        /* current standard */
        int             cur_bw;         /* current black/white status */
@@ -174,7 +174,7 @@ static struct saa7146_standard hexium_standards[] = {
                .h_offset       = 1,    .h_pixels       = 720,
                .v_max_out      = 576,  .h_max_out      = 768,
        }
-};             
+};
 
 /* bring hardware to a sane state. this has to be done, just in case someone
    wants to capture from this device before it has been properly initialized.
@@ -311,7 +311,7 @@ static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        struct saa7146_dev *dev = fh->dev;
        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 /*
-       struct saa7146_vv *vv = dev->vv_data; 
+       struct saa7146_vv *vv = dev->vv_data;
 */
        switch (cmd) {
        case VIDIOC_ENUMINPUT:
index aad4a18..137c473 100644 (file)
@@ -3,7 +3,7 @@
 
     Visit http://www.mihu.de/linux/saa7146/ and follow the link
     to "hexium" for further details about this card.
-    
+
     Copyright (C) 2003 Michael Hunold <michael@mihu.de>
 
     This program is free software; you can redistribute it and/or modify
@@ -69,7 +69,7 @@ struct hexium
 {
        int type;
        struct video_device     *video_dev;
-       struct i2c_adapter      i2c_adapter;    
+       struct i2c_adapter      i2c_adapter;
 
        int cur_input;  /* current input */
 };
@@ -86,7 +86,7 @@ static u8 hexium_saa7110[53]={
 };
 
 static struct {
-       struct hexium_data data[8];     
+       struct hexium_data data[8];
 } hexium_input_select[] = {
 {
        { /* cvbs 1 */
@@ -153,7 +153,7 @@ static struct {
                { 0x30, 0x60 },
                { 0x31, 0xB5 }, // ??
                { 0x21, 0x03 },
-       } 
+       }
 }, {
        { /* y/c 1 */
                { 0x06, 0x80 },
@@ -187,7 +187,7 @@ static struct {
                { 0x31, 0x75 },
                { 0x21, 0x21 },
        }
-}      
+}
 };
 
 static struct saa7146_standard hexium_standards[] = {
@@ -207,7 +207,7 @@ static struct saa7146_standard hexium_standards[] = {
                .h_offset       = 1,    .h_pixels       = 720,
                .v_max_out      = 576,  .h_max_out      = 768,
        }
-};             
+};
 
 /* this is only called for old HV-PCI6/Orion cards
    without eeprom */
@@ -272,7 +272,7 @@ static int hexium_probe(struct saa7146_dev *dev)
                return 0;
        }
 
-       /* check if this is an old hexium Orion card by looking at 
+       /* check if this is an old hexium Orion card by looking at
           a saa7110 at address 0x4e */
        if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
                printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");
@@ -314,7 +314,7 @@ static int hexium_set_input(struct hexium *hexium, int input)
 {
        union i2c_smbus_data data;
        int i = 0;
-       
+
        DEB_D((".\n"));
 
        for (i = 0; i < 8; i++) {
@@ -375,7 +375,7 @@ static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        struct saa7146_dev *dev = fh->dev;
        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 /*
-       struct saa7146_vv *vv = dev->vv_data; 
+       struct saa7146_vv *vv = dev->vv_data;
 */
        switch (cmd) {
        case VIDIOC_ENUMINPUT:
index 58b0e69..95bacf4 100644 (file)
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
 
-/* Mark Phalan <phalanm@o2.ie> */
-static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
-       [  0 ] = KEY_KP0,
-       [  1 ] = KEY_KP1,
-       [  2 ] = KEY_KP2,
-       [  3 ] = KEY_KP3,
-       [  4 ] = KEY_KP4,
-       [  5 ] = KEY_KP5,
-       [  6 ] = KEY_KP6,
-       [  7 ] = KEY_KP7,
-       [  8 ] = KEY_KP8,
-       [  9 ] = KEY_KP9,
-
-       [ 18 ] = KEY_POWER,
-       [ 16 ] = KEY_MUTE,
-       [ 31 ] = KEY_VOLUMEDOWN,
-       [ 27 ] = KEY_VOLUMEUP,
-       [ 26 ] = KEY_CHANNELUP,
-       [ 30 ] = KEY_CHANNELDOWN,
-       [ 14 ] = KEY_PAGEUP,
-       [ 29 ] = KEY_PAGEDOWN,
-       [ 19 ] = KEY_SOUND,
-
-       [ 24 ] = KEY_KPPLUSMINUS,       /* CH +/- */
-       [ 22 ] = KEY_SUBTITLE,          /* CC */
-       [ 13 ] = KEY_TEXT,              /* TTX */
-       [ 11 ] = KEY_TV,                /* AIR/CBL */
-       [ 17 ] = KEY_PC,                /* PC/TV */
-       [ 23 ] = KEY_OK,                /* CH RTN */
-       [ 25 ] = KEY_MODE,              /* FUNC */
-       [ 12 ] = KEY_SEARCH,            /* AUTOSCAN */
-
-       /* Not sure what to do with these ones! */
-       [ 15 ] = KEY_SELECT,            /* SOURCE */
-       [ 10 ] = KEY_KPPLUS,            /* +100 */
-       [ 20 ] = KEY_KPEQUAL,           /* SYNC */
-       [ 28 ] = KEY_MEDIA,             /* PC/TV */
-};
-
 /* ----------------------------------------------------------------------- */
 /* insmod parameters                                                       */
 
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
 
+static int hauppauge = 0;
+module_param(hauppauge, int, 0644);    /* Choose Hauppauge remote */
+MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)");
+
+
 #define DEVNAME "ir-kbd-i2c"
 #define dprintk(level, fmt, arg...)    if (debug >= level) \
        printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
@@ -336,7 +302,11 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                name        = "Hauppauge";
                ir->get_key = get_key_haup;
                ir_type     = IR_TYPE_RC5;
-               ir_codes    = ir_codes_rc5_tv;
+               if (hauppauge == 1) {
+                       ir_codes    = ir_codes_hauppauge_new;
+               } else {
+                       ir_codes    = ir_codes_rc5_tv;
+               }
                break;
        case 0x30:
                name        = "KNC One";
index 2869464..850bee9 100644 (file)
@@ -925,7 +925,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                if (p->palette != VIDEO_PALETTE_YUV422)
                        return -EINVAL;
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
                                      p->brightness >> 10);
                sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE,
@@ -935,7 +935,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST,
                                      p->contrast >> 10);
                meye.picture = *p;
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -946,21 +946,21 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                if (*i < 0 || *i >= gbuffers)
                        return -EINVAL;
 
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
 
                switch (meye.grab_buffer[*i].state) {
 
                case MEYE_BUF_UNUSED:
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EINVAL;
                case MEYE_BUF_USING:
                        if (file->f_flags & O_NONBLOCK) {
-                               up(&meye.lock);
+                               mutex_unlock(&meye.lock);
                                return -EAGAIN;
                        }
                        if (wait_event_interruptible(meye.proc_list,
                                                     (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
-                               up(&meye.lock);
+                               mutex_unlock(&meye.lock);
                                return -EINTR;
                        }
                        /* fall through */
@@ -968,7 +968,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
                        kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
                }
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -987,7 +987,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED)
                        return -EBUSY;
 
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                if (vm->width == 640 && vm->height == 480) {
                        if (meye.params.subsample) {
                                meye.params.subsample = 0;
@@ -999,7 +999,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                                restart = 1;
                        }
                } else {
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EINVAL;
                }
 
@@ -1007,7 +1007,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        mchip_continuous_start();
                meye.grab_buffer[vm->frame].state = MEYE_BUF_USING;
                kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int));
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1039,7 +1039,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                if (jp->framerate > 31)
                        return -EINVAL;
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                if (meye.params.subsample != jp->subsample ||
                    meye.params.quality != jp->quality)
                        mchip_hic_stop();       /* need restart */
@@ -1050,7 +1050,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                                      meye.params.agc);
                sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
                                      meye.params.picture);
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1068,12 +1068,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                }
                if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
                        return -EBUSY;
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
                        mchip_cont_compression_start();
                meye.grab_buffer[*nb].state = MEYE_BUF_USING;
                kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1084,20 +1084,20 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                if (*i < 0 || *i >= gbuffers)
                        return -EINVAL;
 
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                switch (meye.grab_buffer[*i].state) {
 
                case MEYE_BUF_UNUSED:
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EINVAL;
                case MEYE_BUF_USING:
                        if (file->f_flags & O_NONBLOCK) {
-                               up(&meye.lock);
+                               mutex_unlock(&meye.lock);
                                return -EAGAIN;
                        }
                        if (wait_event_interruptible(meye.proc_list,
                                                     (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
-                               up(&meye.lock);
+                               mutex_unlock(&meye.lock);
                                return -EINTR;
                        }
                        /* fall through */
@@ -1106,7 +1106,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
                }
                *i = meye.grab_buffer[*i].size;
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1116,14 +1116,14 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
                        return -EBUSY;
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                meye.grab_buffer[0].state = MEYE_BUF_USING;
                mchip_take_picture();
                mchip_get_picture(
                        meye.grab_fbuffer,
                        mchip_hsize() * mchip_vsize() * 2);
                meye.grab_buffer[0].state = MEYE_BUF_DONE;
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1134,7 +1134,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
                        return -EBUSY;
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                meye.grab_buffer[0].state = MEYE_BUF_USING;
                *len = -1;
                while (*len == -1) {
@@ -1142,7 +1142,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
                }
                meye.grab_buffer[0].state = MEYE_BUF_DONE;
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1285,7 +1285,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_S_CTRL: {
                struct v4l2_control *c = arg;
 
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                switch (c->id) {
                case V4L2_CID_BRIGHTNESS:
                        sonypi_camera_command(
@@ -1329,17 +1329,17 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        meye.params.framerate = c->value;
                        break;
                default:
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EINVAL;
                }
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
        case VIDIOC_G_CTRL: {
                struct v4l2_control *c = arg;
 
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                switch (c->id) {
                case V4L2_CID_BRIGHTNESS:
                        c->value = meye.picture.brightness >> 10;
@@ -1369,10 +1369,10 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        c->value = meye.params.framerate;
                        break;
                default:
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EINVAL;
                }
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1469,7 +1469,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                    f->fmt.pix.field != V4L2_FIELD_NONE)
                        return -EINVAL;
                f->fmt.pix.field = V4L2_FIELD_NONE;
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                if (f->fmt.pix.width <= 320) {
                        f->fmt.pix.width = 320;
                        f->fmt.pix.height = 240;
@@ -1487,7 +1487,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
                        break;
                }
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
                f->fmt.pix.sizeimage = f->fmt.pix.height *
                                       f->fmt.pix.bytesperline;
@@ -1509,11 +1509,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        /* already allocated, no modifications */
                        break;
                }
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                if (meye.grab_fbuffer) {
                        for (i = 0; i < gbuffers; i++)
                                if (meye.vma_use_count[i]) {
-                                       up(&meye.lock);
+                                       mutex_unlock(&meye.lock);
                                        return -EINVAL;
                                }
                        rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
@@ -1525,12 +1525,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                if (!meye.grab_fbuffer) {
                        printk(KERN_ERR "meye: v4l framebuffer allocation"
                                        " failed\n");
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -ENOMEM;
                }
                for (i = 0; i < gbuffers; i++)
                        meye.vma_use_count[i] = 0;
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1569,12 +1569,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
                        return -EINVAL;
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                buf->flags |= V4L2_BUF_FLAG_QUEUED;
                buf->flags &= ~V4L2_BUF_FLAG_DONE;
                meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
                kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1587,23 +1587,23 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                if (buf->memory != V4L2_MEMORY_MMAP)
                        return -EINVAL;
 
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EAGAIN;
                }
                if (wait_event_interruptible(meye.proc_list,
                                             kfifo_len(meye.doneq) != 0) < 0) {
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EINTR;
                }
                if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
                               sizeof(int))) {
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EBUSY;
                }
                if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EINVAL;
                }
                buf->index = reqnr;
@@ -1616,12 +1616,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                buf->m.offset = reqnr * gbufsize;
                buf->length = gbufsize;
                meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
        case VIDIOC_STREAMON: {
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                switch (meye.mchip_mode) {
                case MCHIP_HIC_MODE_CONT_OUT:
                        mchip_continuous_start();
@@ -1630,23 +1630,23 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
                        mchip_cont_compression_start();
                        break;
                default:
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EINVAL;
                }
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
        case VIDIOC_STREAMOFF: {
                int i;
 
-               down(&meye.lock);
+               mutex_lock(&meye.lock);
                mchip_hic_stop();
                kfifo_reset(meye.grabq);
                kfifo_reset(meye.doneq);
                for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
                        meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                break;
        }
 
@@ -1672,11 +1672,11 @@ static unsigned int meye_poll(struct file *file, poll_table *wait)
 {
        unsigned int res = 0;
 
-       down(&meye.lock);
+       mutex_lock(&meye.lock);
        poll_wait(file, &meye.proc_list, wait);
        if (kfifo_len(meye.doneq))
                res = POLLIN | POLLRDNORM;
-       up(&meye.lock);
+       mutex_unlock(&meye.lock);
        return res;
 }
 
@@ -1704,9 +1704,9 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        unsigned long page, pos;
 
-       down(&meye.lock);
+       mutex_lock(&meye.lock);
        if (size > gbuffers * gbufsize) {
-               up(&meye.lock);
+               mutex_unlock(&meye.lock);
                return -EINVAL;
        }
        if (!meye.grab_fbuffer) {
@@ -1716,7 +1716,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
                meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);
                if (!meye.grab_fbuffer) {
                        printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -ENOMEM;
                }
                for (i = 0; i < gbuffers; i++)
@@ -1727,7 +1727,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
        while (size > 0) {
                page = vmalloc_to_pfn((void *)pos);
                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       up(&meye.lock);
+                       mutex_unlock(&meye.lock);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -1744,7 +1744,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
        vma->vm_private_data = (void *) (offset / gbufsize);
        meye_vm_open(vma);
 
-       up(&meye.lock);
+       mutex_unlock(&meye.lock);
        return 0;
 }
 
@@ -1913,7 +1913,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
                goto outvideoreg;
        }
 
-       init_MUTEX(&meye.lock);
+       mutex_init(&meye.lock);
        init_waitqueue_head(&meye.proc_list);
        meye.picture.depth = 16;
        meye.picture.palette = VIDEO_PALETTE_YUV422;
index e8cd897..0d09a0e 100644 (file)
 
 /* private API definitions */
 #include <linux/meye.h>
+#include <linux/mutex.h>
+
 
 /* Enable jpg software correction */
 #define MEYE_JPEG_CORRECTION   1
@@ -301,7 +303,7 @@ struct meye {
                                        /* list of buffers */
        struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
        int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
-       struct semaphore lock;          /* semaphore for open/mmap... */
+       struct mutex lock;              /* mutex for open/mmap... */
        struct kfifo *grabq;            /* queue for buffers to be grabbed */
        spinlock_t grabq_lock;          /* lock protecting the queue */
        struct kfifo *doneq;            /* queue for grabbed buffers */
index 69ed369..11ea976 100644 (file)
@@ -411,9 +411,9 @@ static int msp_mode_v4l2_to_v4l1(int rxsubchans)
        if (rxsubchans & V4L2_TUNER_SUB_STEREO)
                mode |= VIDEO_SOUND_STEREO;
        if (rxsubchans & V4L2_TUNER_SUB_LANG2)
-               mode |= VIDEO_SOUND_LANG2;
+               mode |= VIDEO_SOUND_LANG2 | VIDEO_SOUND_STEREO;
        if (rxsubchans & V4L2_TUNER_SUB_LANG1)
-               mode |= VIDEO_SOUND_LANG1;
+               mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_STEREO;
        if (mode == 0)
                mode |= VIDEO_SOUND_MONO;
        return mode;
@@ -430,21 +430,6 @@ static int msp_mode_v4l1_to_v4l2(int mode)
        return V4L2_TUNER_MODE_MONO;
 }
 
-static void msp_any_detect_stereo(struct i2c_client *client)
-{
-       struct msp_state *state  = i2c_get_clientdata(client);
-
-       switch (state->opmode) {
-       case OPMODE_MANUAL:
-       case OPMODE_AUTODETECT:
-               autodetect_stereo(client);
-               break;
-       case OPMODE_AUTOSELECT:
-               msp34xxg_detect_stereo(client);
-               break;
-       }
-}
-
 static struct v4l2_queryctrl msp_qctrl_std[] = {
        {
                .id            = V4L2_CID_AUDIO_VOLUME,
@@ -506,22 +491,6 @@ static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
 };
 
 
-static void msp_any_set_audmode(struct i2c_client *client, int audmode)
-{
-       struct msp_state *state = i2c_get_clientdata(client);
-
-       switch (state->opmode) {
-       case OPMODE_MANUAL:
-       case OPMODE_AUTODETECT:
-               state->watch_stereo = 0;
-               msp3400c_setstereo(client, audmode);
-               break;
-       case OPMODE_AUTOSELECT:
-               msp34xxg_set_audmode(client, audmode);
-               break;
-       }
-}
-
 static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 {
        struct msp_state *state = i2c_get_clientdata(client);
@@ -653,11 +622,10 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                }
                if (scart) {
                        state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       state->audmode = V4L2_TUNER_MODE_STEREO;
                        msp_set_scart(client, scart, 0);
                        msp_write_dsp(client, 0x000d, 0x1900);
                        if (state->opmode != OPMODE_AUTOSELECT)
-                               msp3400c_setstereo(client, state->audmode);
+                               msp_set_audmode(client);
                }
                msp_wake_thread(client);
                break;
@@ -671,8 +639,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                switch (state->opmode) {
                case OPMODE_MANUAL:
                        /* set msp3400 to FM radio mode */
-                       msp3400c_setmode(client, MSP_MODE_FM_RADIO);
-                       msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+                       msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+                       msp3400c_set_carrier(client, MSP_CARRIER(10.7),
                                            MSP_CARRIER(10.7));
                        msp_set_audio(client);
                        break;
@@ -706,7 +674,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                if (state->radio)
                        break;
                if (state->opmode == OPMODE_AUTOSELECT)
-                       msp_any_detect_stereo(client);
+                       msp_detect_stereo(client);
                va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans);
                break;
        }
@@ -722,8 +690,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                state->treble = va->treble;
                msp_set_audio(client);
 
-               if (va->mode != 0 && state->radio == 0)
-                       msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode));
+               if (va->mode != 0 && state->radio == 0) {
+                       state->audmode = msp_mode_v4l1_to_v4l2(va->mode);
+               }
                break;
        }
 
@@ -831,11 +800,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        return -EINVAL;
                }
 
-               msp_any_detect_stereo(client);
-               if (state->audmode == V4L2_TUNER_MODE_STEREO) {
-                       a->capability = V4L2_AUDCAP_STEREO;
-               }
-
+               a->capability = V4L2_AUDCAP_STEREO;
+               a->mode = 0;  /* TODO: add support for AVL */
                break;
        }
 
@@ -865,16 +831,10 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                }
                if (scart) {
                        state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       state->audmode = V4L2_TUNER_MODE_STEREO;
                        msp_set_scart(client, scart, 0);
                        msp_write_dsp(client, 0x000d, 0x1900);
                }
-               if (sarg->capability == V4L2_AUDCAP_STEREO) {
-                       state->audmode = V4L2_TUNER_MODE_STEREO;
-               } else {
-                       state->audmode &= ~V4L2_TUNER_MODE_STEREO;
-               }
-               msp_any_set_audmode(client, state->audmode);
+               msp_set_audmode(client);
                msp_wake_thread(client);
                break;
        }
@@ -886,7 +846,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                if (state->radio)
                        break;
                if (state->opmode == OPMODE_AUTOSELECT)
-                       msp_any_detect_stereo(client);
+                       msp_detect_stereo(client);
                vt->audmode    = state->audmode;
                vt->rxsubchans = state->rxsubchans;
                vt->capability = V4L2_TUNER_CAP_STEREO |
@@ -898,11 +858,11 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        {
                struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
 
-               if (state->radio)
+               if (state->radio)  /* TODO: add mono/stereo support for radio */
                        break;
+               state->audmode = vt->audmode;
                /* only set audmode */
-               if (vt->audmode != -1 && vt->audmode != 0)
-                       msp_any_set_audmode(client, vt->audmode);
+               msp_set_audmode(client);
                break;
        }
 
@@ -927,7 +887,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        return -EINVAL;
                }
                break;
-
        }
 
        case VIDIOC_S_AUDOUT:
@@ -993,7 +952,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                const char *p;
 
                if (state->opmode == OPMODE_AUTOSELECT)
-                       msp_any_detect_stereo(client);
+                       msp_detect_stereo(client);
                v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
                                client->name, state->rev1, state->rev2);
                v4l_info(client, "Audio:    volume %d%s\n",
@@ -1094,6 +1053,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
 
        memset(state, 0, sizeof(*state));
        state->v4l2_std = V4L2_STD_NTSC;
+       state->audmode = V4L2_TUNER_MODE_LANG1;
        state->volume = 58880;  /* 0db gain */
        state->balance = 32768; /* 0db gain */
        state->bass = 32768;
index 2072c3e..852ab6a 100644 (file)
@@ -109,7 +109,7 @@ static struct msp3400c_init_data_dem {
                {-2, -8, -10, 10, 50, 86},
                {-4, -12, -9, 23, 79, 126},
                MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-               0x00c6, 0x0140, 0x0120, 0x7c03
+               0x00c6, 0x0140, 0x0120, 0x7c00
        },
 };
 
@@ -154,54 +154,60 @@ const char *msp_standard_std_name(int std)
        return "unknown";
 }
 
-void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
+static void msp_set_source(struct i2c_client *client, u16 src)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       if (msp_dolby) {
+               msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
+               msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
+       } else {
+               msp_write_dsp(client, 0x0008, src);
+               msp_write_dsp(client, 0x0009, src);
+       }
+       msp_write_dsp(client, 0x000a, src);
+       msp_write_dsp(client, 0x000b, src);
+       msp_write_dsp(client, 0x000c, src);
+       if (state->has_scart23_in_scart2_out)
+               msp_write_dsp(client, 0x0041, src);
+}
+
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2)
 {
        msp_write_dem(client, 0x0093, cdo1 & 0xfff);
        msp_write_dem(client, 0x009b, cdo1 >> 12);
        msp_write_dem(client, 0x00a3, cdo2 & 0xfff);
        msp_write_dem(client, 0x00ab, cdo2 >> 12);
-       msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
+       msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */
 }
 
-void msp3400c_setmode(struct i2c_client *client, int type)
+void msp3400c_set_mode(struct i2c_client *client, int mode)
 {
        struct msp_state *state = i2c_get_clientdata(client);
+       struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
        int i;
 
-       v4l_dbg(1, msp_debug, client, "setmode: %d\n", type);
-       state->mode       = type;
-       state->audmode    = V4L2_TUNER_MODE_MONO;
+       v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode);
+       state->mode = mode;
        state->rxsubchans = V4L2_TUNER_SUB_MONO;
 
-       msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv);
+       msp_write_dem(client, 0x00bb, data->ad_cv);
 
        for (i = 5; i >= 0; i--)               /* fir 1 */
-               msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]);
+               msp_write_dem(client, 0x0001, data->fir1[i]);
 
        msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */
        msp_write_dem(client, 0x0005, 0x0040);
        msp_write_dem(client, 0x0005, 0x0000);
        for (i = 5; i >= 0; i--)
-               msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]);
+               msp_write_dem(client, 0x0005, data->fir2[i]);
 
-       msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg);
+       msp_write_dem(client, 0x0083, data->mode_reg);
 
-       msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1,
-                           msp3400c_init_data[type].cdo2);
+       msp3400c_set_carrier(client, data->cdo1, data->cdo2);
 
-       msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/
-
-       if (msp_dolby) {
-               msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
-               msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */
-               msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
-       } else {
-               msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src);
-               msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src);
-               msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src);
-       }
-       msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src);
-       msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix);
+       msp_set_source(client, data->dsp_src);
+       msp_write_dsp(client, 0x000e, data->dsp_matrix);
 
        if (state->has_nicam) {
                /* nicam prescale */
@@ -209,29 +215,31 @@ void msp3400c_setmode(struct i2c_client *client, int type)
        }
 }
 
-/* turn on/off nicam + stereo */
-void msp3400c_setstereo(struct i2c_client *client, int mode)
+/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP,
+   nor do they support stereo BTSC. */
+static void msp3400c_set_audmode(struct i2c_client *client)
 {
        static char *strmode[] = { "mono", "stereo", "lang2", "lang1" };
        struct msp_state *state = i2c_get_clientdata(client);
-       int nicam = 0;          /* channel source: FM/AM or nicam */
-       int src = 0;
+       char *modestr = (state->audmode >= 0 && state->audmode < 4) ?
+               strmode[state->audmode] : "unknown";
+       int src = 0;    /* channel source: FM/AM, nicam or SCART */
 
        if (state->opmode == OPMODE_AUTOSELECT) {
                /* this method would break everything, let's make sure
                 * it's never called
                 */
-               v4l_dbg(1, msp_debug, client, "setstereo called with mode=%d instead of set_source (ignored)\n",
-                    mode);
+               v4l_dbg(1, msp_debug, client,
+                       "set_audmode called with mode=%d instead of set_source (ignored)\n",
+                       state->audmode);
                return;
        }
 
        /* switch demodulator */
        switch (state->mode) {
        case MSP_MODE_FM_TERRA:
-               v4l_dbg(1, msp_debug, client, "FM setstereo: %s\n", strmode[mode]);
-               msp3400c_setcarrier(client, state->second, state->main);
-               switch (mode) {
+               v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr);
+               switch (state->audmode) {
                case V4L2_TUNER_MODE_STEREO:
                        msp_write_dsp(client, 0x000e, 0x3001);
                        break;
@@ -243,50 +251,49 @@ void msp3400c_setstereo(struct i2c_client *client, int mode)
                }
                break;
        case MSP_MODE_FM_SAT:
-               v4l_dbg(1, msp_debug, client, "SAT setstereo: %s\n", strmode[mode]);
-               switch (mode) {
+               v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr);
+               switch (state->audmode) {
                case V4L2_TUNER_MODE_MONO:
-                       msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+                       msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
                        break;
                case V4L2_TUNER_MODE_STEREO:
-                       msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+                       msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
                        break;
                case V4L2_TUNER_MODE_LANG1:
-                       msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+                       msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
                        break;
                case V4L2_TUNER_MODE_LANG2:
-                       msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+                       msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
                        break;
                }
                break;
        case MSP_MODE_FM_NICAM1:
        case MSP_MODE_FM_NICAM2:
        case MSP_MODE_AM_NICAM:
-               v4l_dbg(1, msp_debug, client, "NICAM setstereo: %s\n",strmode[mode]);
-               msp3400c_setcarrier(client,state->second,state->main);
+               v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
+               msp3400c_set_carrier(client, state->second, state->main);
                if (state->nicam_on)
-                       nicam=0x0100;
+                       src = 0x0100;  /* NICAM */
                break;
        case MSP_MODE_BTSC:
-               v4l_dbg(1, msp_debug, client, "BTSC setstereo: %s\n",strmode[mode]);
-               nicam=0x0300;
+               v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
                break;
        case MSP_MODE_EXTERN:
-               v4l_dbg(1, msp_debug, client, "extern setstereo: %s\n",strmode[mode]);
-               nicam = 0x0200;
+               v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
+               src = 0x0200;  /* SCART */
                break;
        case MSP_MODE_FM_RADIO:
-               v4l_dbg(1, msp_debug, client, "FM-Radio setstereo: %s\n",strmode[mode]);
+               v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr);
                break;
        default:
-               v4l_dbg(1, msp_debug, client, "mono setstereo\n");
+               v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
                return;
        }
 
        /* switch audio */
-       switch (mode) {
+       switch (state->audmode) {
        case V4L2_TUNER_MODE_STEREO:
-               src = 0x0020 | nicam;
+               src |= 0x0020;
                break;
        case V4L2_TUNER_MODE_MONO:
                if (state->mode == MSP_MODE_AM_NICAM) {
@@ -297,29 +304,22 @@ void msp3400c_setstereo(struct i2c_client *client, int mode)
                        src = 0x0200;
                        break;
                }
+               if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+                       src = 0x0030;
+               break;
        case V4L2_TUNER_MODE_LANG1:
-               src = 0x0000 | nicam;
+               /* switch to stereo for stereo transmission, otherwise
+                  keep first language */
+               if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
+                       src |= 0x0020;
                break;
        case V4L2_TUNER_MODE_LANG2:
-               src = 0x0010 | nicam;
+               src |= 0x0010;
                break;
        }
-       v4l_dbg(1, msp_debug, client, "setstereo final source/matrix = 0x%x\n", src);
+       v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
 
-       if (msp_dolby) {
-               msp_write_dsp(client, 0x0008, 0x0520);
-               msp_write_dsp(client, 0x0009, 0x0620);
-               msp_write_dsp(client, 0x000a, src);
-               msp_write_dsp(client, 0x000b, src);
-       } else {
-               msp_write_dsp(client, 0x0008, src);
-               msp_write_dsp(client, 0x0009, src);
-               msp_write_dsp(client, 0x000a, src);
-               msp_write_dsp(client, 0x000b, src);
-               msp_write_dsp(client, 0x000c, src);
-               if (state->has_scart23_in_scart2_out)
-                       msp_write_dsp(client, 0x0041, src);
-       }
+       msp_set_source(client, src);
 }
 
 static void msp3400c_print_mode(struct i2c_client *client)
@@ -347,12 +347,12 @@ static void msp3400c_print_mode(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
-int autodetect_stereo(struct i2c_client *client)
+static int msp3400c_detect_stereo(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
        int val;
        int rxsubchans = state->rxsubchans;
-       int newnicam   = state->nicam_on;
+       int newnicam = state->nicam_on;
        int update = 0;
 
        switch (state->mode) {
@@ -362,7 +362,7 @@ int autodetect_stereo(struct i2c_client *client)
                        val -= 65536;
                v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
                if (val > 4096) {
-                       rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+                       rxsubchans = V4L2_TUNER_SUB_STEREO;
                } else if (val < -4096) {
                        rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
                } else {
@@ -386,14 +386,11 @@ int autodetect_stereo(struct i2c_client *client)
                                break;
                        case 1:
                        case 9:
-                               rxsubchans = V4L2_TUNER_SUB_MONO
-                                       | V4L2_TUNER_SUB_LANG1;
+                               rxsubchans = V4L2_TUNER_SUB_MONO;
                                break;
                        case 2:
                        case 10:
-                               rxsubchans = V4L2_TUNER_SUB_MONO
-                                       | V4L2_TUNER_SUB_LANG1
-                                       | V4L2_TUNER_SUB_LANG2;
+                               rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
                                break;
                        default:
                                rxsubchans = V4L2_TUNER_SUB_MONO;
@@ -405,30 +402,17 @@ int autodetect_stereo(struct i2c_client *client)
                        rxsubchans = V4L2_TUNER_SUB_MONO;
                }
                break;
-       case MSP_MODE_BTSC:
-               val = msp_read_dem(client, 0x200);
-               v4l_dbg(2, msp_debug, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
-                       val,
-                       (val & 0x0002) ? "no"     : "yes",
-                       (val & 0x0004) ? "no"     : "yes",
-                       (val & 0x0040) ? "stereo" : "mono",
-                       (val & 0x0080) ? ", nicam 2nd mono" : "",
-                       (val & 0x0100) ? ", bilingual/SAP"  : "");
-               rxsubchans = V4L2_TUNER_SUB_MONO;
-               if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO;
-               if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1;
-               break;
        }
        if (rxsubchans != state->rxsubchans) {
                update = 1;
-               v4l_dbg(1, msp_debug, client, "watch: rxsubchans %d => %d\n",
-                       state->rxsubchans,rxsubchans);
+               v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
+                       state->rxsubchans, rxsubchans);
                state->rxsubchans = rxsubchans;
        }
        if (newnicam != state->nicam_on) {
                update = 1;
                v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n",
-                       state->nicam_on,newnicam);
+                       state->nicam_on, newnicam);
                state->nicam_on = newnicam;
        }
        return update;
@@ -443,13 +427,8 @@ static void watch_stereo(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
 
-       if (autodetect_stereo(client)) {
-               if (state->rxsubchans & V4L2_TUNER_SUB_STEREO)
-                       msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
-               else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1)
-                       msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
-               else
-                       msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+       if (msp3400c_detect_stereo(client)) {
+               msp3400c_set_audmode(client);
        }
 
        if (msp_once)
@@ -461,7 +440,7 @@ int msp3400c_thread(void *data)
        struct i2c_client *client = data;
        struct msp_state *state = i2c_get_clientdata(client);
        struct msp3400c_carrier_detect *cd;
-       int count, max1,max2,val1,val2, val,this;
+       int count, max1, max2, val1, val2, val, this;
 
 
        v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
@@ -471,7 +450,7 @@ int msp3400c_thread(void *data)
                v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
 
        restart:
-               v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
+               v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
                state->restart = 0;
                if (kthread_should_stop())
                        break;
@@ -485,13 +464,14 @@ int msp3400c_thread(void *data)
 
                /* mute */
                msp_set_mute(client);
-               msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
+               msp3400c_set_mode(client, MSP_MODE_AM_DETECT /* +1 */ );
                val1 = val2 = 0;
                max1 = max2 = -1;
                state->watch_stereo = 0;
+               state->nicam_on = 0;
 
                /* some time for the tuner to sync */
-               if (msp_sleep(state,200))
+               if (msp_sleep(state, 200))
                        goto restart;
 
                /* carrier detect pass #1 -- main carrier */
@@ -506,7 +486,7 @@ int msp3400c_thread(void *data)
                }
 
                for (this = 0; this < count; this++) {
-                       msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+                       msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
                        if (msp_sleep(state,100))
                                goto restart;
                        val = msp_read_dsp(client, 0x1b);
@@ -542,7 +522,7 @@ int msp3400c_thread(void *data)
                        max2 = 0;
                }
                for (this = 0; this < count; this++) {
-                       msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
+                       msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
                        if (msp_sleep(state,100))
                                goto restart;
                        val = msp_read_dsp(client, 0x1b);
@@ -554,22 +534,20 @@ int msp3400c_thread(void *data)
                }
 
                /* program the msp3400 according to the results */
-               state->main   = msp3400c_carrier_detect_main[max1].cdo;
+               state->main = msp3400c_carrier_detect_main[max1].cdo;
                switch (max1) {
                case 1: /* 5.5 */
                        if (max2 == 0) {
                                /* B/G FM-stereo */
                                state->second = msp3400c_carrier_detect_55[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-                               state->nicam_on = 0;
-                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+                               msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
                                state->watch_stereo = 1;
                        } else if (max2 == 1 && state->has_nicam) {
                                /* B/G NICAM */
                                state->second = msp3400c_carrier_detect_55[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+                               msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
+                               msp3400c_set_carrier(client, state->second, state->main);
                                state->nicam_on = 1;
-                               msp3400c_setcarrier(client, state->second, state->main);
                                state->watch_stereo = 1;
                        } else {
                                goto no_second;
@@ -578,35 +556,31 @@ int msp3400c_thread(void *data)
                case 2: /* 6.0 */
                        /* PAL I NICAM */
                        state->second = MSP_CARRIER(6.552);
-                       msp3400c_setmode(client, MSP_MODE_FM_NICAM2);
+                       msp3400c_set_mode(client, MSP_MODE_FM_NICAM2);
+                       msp3400c_set_carrier(client, state->second, state->main);
                        state->nicam_on = 1;
-                       msp3400c_setcarrier(client, state->second, state->main);
                        state->watch_stereo = 1;
                        break;
                case 3: /* 6.5 */
                        if (max2 == 1 || max2 == 2) {
                                /* D/K FM-stereo */
                                state->second = msp3400c_carrier_detect_65[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-                               state->nicam_on = 0;
-                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+                               msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
                                state->watch_stereo = 1;
                        } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) {
                                /* L NICAM or AM-mono */
                                state->second = msp3400c_carrier_detect_65[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_AM_NICAM);
-                               state->nicam_on = 0;
-                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
-                               msp3400c_setcarrier(client, state->second, state->main);
+                               msp3400c_set_mode(client, MSP_MODE_AM_NICAM);
+                               msp3400c_set_carrier(client, state->second, state->main);
                                /* volume prescale for SCART (AM mono input) */
                                msp_write_dsp(client, 0x000d, 0x1900);
                                state->watch_stereo = 1;
                        } else if (max2 == 0 && state->has_nicam) {
                                /* D/K NICAM */
                                state->second = msp3400c_carrier_detect_65[max2].cdo;
-                               msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
+                               msp3400c_set_mode(client, MSP_MODE_FM_NICAM1);
+                               msp3400c_set_carrier(client, state->second, state->main);
                                state->nicam_on = 1;
-                               msp3400c_setcarrier(client, state->second, state->main);
                                state->watch_stereo = 1;
                        } else {
                                goto no_second;
@@ -616,23 +590,25 @@ int msp3400c_thread(void *data)
                default:
                no_second:
                        state->second = msp3400c_carrier_detect_main[max1].cdo;
-                       msp3400c_setmode(client, MSP_MODE_FM_TERRA);
-                       state->nicam_on = 0;
-                       msp3400c_setcarrier(client, state->second, state->main);
+                       msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
+                       msp3400c_set_carrier(client, state->second, state->main);
                        state->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
                        break;
                }
 
                /* unmute */
                msp_set_audio(client);
+               msp3400c_set_audmode(client);
 
                if (msp_debug)
                        msp3400c_print_mode(client);
 
-               /* monitor tv audio mode */
+               /* monitor tv audio mode, the first time don't wait
+                  so long to get a quick stereo/bilingual result */
+               if (msp_sleep(state, 1000))
+                       goto restart;
                while (state->watch_stereo) {
-                       if (msp_sleep(state,5000))
+                       if (msp_sleep(state, 5000))
                                goto restart;
                        watch_stereo(client);
                }
@@ -656,7 +632,7 @@ int msp3410d_thread(void *data)
                v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
 
        restart:
-               v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
+               v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
                state->restart = 0;
                if (kthread_should_stop())
                        break;
@@ -681,9 +657,10 @@ int msp3410d_thread(void *data)
                else
                        std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1;
                state->watch_stereo = 0;
+               state->nicam_on = 0;
 
                if (msp_debug)
-                       v4l_dbg(1, msp_debug, client, "setting standard: %s (0x%04x)\n",
+                       v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
                               msp_standard_std_name(std), std);
 
                if (std != 1) {
@@ -700,7 +677,7 @@ int msp3410d_thread(void *data)
                                val = msp_read_dem(client, 0x7e);
                                if (val < 0x07ff)
                                        break;
-                               v4l_dbg(1, msp_debug, client, "detection still in progress\n");
+                               v4l_dbg(2, msp_debug, client, "detection still in progress\n");
                        }
                }
                for (i = 0; msp_stdlist[i].name != NULL; i++)
@@ -739,48 +716,34 @@ int msp3410d_thread(void *data)
                        state->rxsubchans = V4L2_TUNER_SUB_STEREO;
                        state->nicam_on = 1;
                        state->watch_stereo = 1;
-                       msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
                        break;
                case 0x0009:
                        state->mode = MSP_MODE_AM_NICAM;
                        state->rxsubchans = V4L2_TUNER_SUB_MONO;
                        state->nicam_on = 1;
-                       msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
                        state->watch_stereo = 1;
                        break;
                case 0x0020: /* BTSC */
-                       /* just turn on stereo */
+                       /* The pre-'G' models only have BTSC-mono */
                        state->mode = MSP_MODE_BTSC;
-                       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       state->nicam_on = 0;
-                       state->watch_stereo = 1;
-                       msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
+                       state->rxsubchans = V4L2_TUNER_SUB_MONO;
                        break;
                case 0x0040: /* FM radio */
                        state->mode = MSP_MODE_FM_RADIO;
                        state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       state->audmode = V4L2_TUNER_MODE_STEREO;
-                       state->nicam_on = 0;
-                       state->watch_stereo = 0;
                        /* not needed in theory if we have radio, but
                           short programming enables carrier mute */
-                       msp3400c_setmode(client, MSP_MODE_FM_RADIO);
-                       msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+                       msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+                       msp3400c_set_carrier(client, MSP_CARRIER(10.7),
                                            MSP_CARRIER(10.7));
-                       /* scart routing */
+                       /* scart routing (this doesn't belong here I think) */
                        msp_set_scart(client,SCART_IN2,0);
-                       /* msp34xx does radio decoding */
-                       msp_write_dsp(client, 0x08, 0x0020);
-                       msp_write_dsp(client, 0x09, 0x0020);
-                       msp_write_dsp(client, 0x0b, 0x0020);
                        break;
                case 0x0003:
                case 0x0004:
                case 0x0005:
                        state->mode = MSP_MODE_FM_TERRA;
                        state->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       state->audmode = V4L2_TUNER_MODE_MONO;
-                       state->nicam_on = 0;
                        state->watch_stereo = 1;
                        break;
                }
@@ -791,11 +754,16 @@ int msp3410d_thread(void *data)
                if (state->has_i2s_conf)
                        msp_write_dem(client, 0x40, state->i2s_mode);
 
-               /* monitor tv audio mode */
+               msp3400c_set_audmode(client);
+
+               /* monitor tv audio mode, the first time don't wait
+                  so long to get a quick stereo/bilingual result */
+               if (msp_sleep(state, 1000))
+                       goto restart;
                while (state->watch_stereo) {
-                       if (msp_sleep(state,5000))
-                               goto restart;
                        watch_stereo(client);
+                       if (msp_sleep(state, 5000))
+                               goto restart;
                }
        }
        v4l_dbg(1, msp_debug, client, "thread: exit\n");
@@ -813,7 +781,7 @@ int msp3410d_thread(void *data)
  * the value for source is the same as bit 15:8 of DSP registers 0x08,
  * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
  *
- * this function replaces msp3400c_setstereo
+ * this function replaces msp3400c_set_audmode
  */
 static void msp34xxg_set_source(struct i2c_client *client, int source)
 {
@@ -826,12 +794,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source)
        int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
 
        v4l_dbg(1, msp_debug, client, "set source to %d (0x%x)\n", source, value);
-       /* Loudspeaker Output */
-       msp_write_dsp(client, 0x08, value);
-       /* SCART1 DA Output */
-       msp_write_dsp(client, 0x0a, value);
-       /* Quasi-peak detector */
-       msp_write_dsp(client, 0x0c, value);
+       msp_set_source(client, value);
        /*
         * set identification threshold. Personally, I
         * I set it to a higher value that the default
@@ -948,13 +911,14 @@ int msp34xxg_thread(void *data)
                if (msp_write_dsp(client, 0x13, state->acb))
                        return -1;
 
-               msp_write_dem(client, 0x40, state->i2s_mode);
+               if (state->has_i2s_conf)
+                       msp_write_dem(client, 0x40, state->i2s_mode);
        }
        v4l_dbg(1, msp_debug, client, "thread: exit\n");
        return 0;
 }
 
-void msp34xxg_detect_stereo(struct i2c_client *client)
+static void msp34xxg_detect_stereo(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
 
@@ -964,11 +928,11 @@ void msp34xxg_detect_stereo(struct i2c_client *client)
 
        state->rxsubchans = 0;
        if (is_stereo)
-               state->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+               state->rxsubchans = V4L2_TUNER_SUB_STEREO;
        else
-               state->rxsubchans |= V4L2_TUNER_SUB_MONO;
+               state->rxsubchans = V4L2_TUNER_SUB_MONO;
        if (is_bilingual) {
-               state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+               state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
                /* I'm supposed to check whether it's SAP or not
                 * and set only LANG2/SAP in this case. Yet, the MSP
                 * does a lot of work to hide this and handle everything
@@ -980,12 +944,12 @@ void msp34xxg_detect_stereo(struct i2c_client *client)
                status, is_stereo, is_bilingual, state->rxsubchans);
 }
 
-void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
+static void msp34xxg_set_audmode(struct i2c_client *client)
 {
        struct msp_state *state = i2c_get_clientdata(client);
        int source;
 
-       switch (audmode) {
+       switch (state->audmode) {
        case V4L2_TUNER_MODE_MONO:
                source = 0; /* mono only */
                break;
@@ -1000,11 +964,40 @@ void msp34xxg_set_audmode(struct i2c_client *client, int audmode)
                source = 4; /* stereo or B */
                break;
        default:
-               audmode = 0;
                source  = 1;
                break;
        }
-       state->audmode = audmode;
        msp34xxg_set_source(client, source);
 }
 
+void msp_set_audmode(struct i2c_client *client)
+{
+       struct msp_state *state = i2c_get_clientdata(client);
+
+       switch (state->opmode) {
+       case OPMODE_MANUAL:
+       case OPMODE_AUTODETECT:
+               state->watch_stereo = 0;
+               msp3400c_set_audmode(client);
+               break;
+       case OPMODE_AUTOSELECT:
+               msp34xxg_set_audmode(client);
+               break;
+       }
+}
+
+void msp_detect_stereo(struct i2c_client *client)
+{
+       struct msp_state *state  = i2c_get_clientdata(client);
+
+       switch (state->opmode) {
+       case OPMODE_MANUAL:
+       case OPMODE_AUTODETECT:
+               msp3400c_detect_stereo(client);
+               break;
+       case OPMODE_AUTOSELECT:
+               msp34xxg_detect_stereo(client);
+               break;
+       }
+}
+
index a9ac57d..6fb5c8c 100644 (file)
@@ -104,14 +104,12 @@ int msp_sleep(struct msp_state *state, int timeout);
 
 /* msp3400-kthreads.c */
 const char *msp_standard_std_name(int std);
-void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2);
-void msp3400c_setmode(struct i2c_client *client, int type);
-void msp3400c_setstereo(struct i2c_client *client, int mode);
-int autodetect_stereo(struct i2c_client *client);
+void msp_set_audmode(struct i2c_client *client);
+void msp_detect_stereo(struct i2c_client *client);
 int msp3400c_thread(void *data);
 int msp3410d_thread(void *data);
 int msp34xxg_thread(void *data);
-void msp34xxg_detect_stereo(struct i2c_client *client);
-void msp34xxg_set_audmode(struct i2c_client *client, int audmode);
+void msp3400c_set_mode(struct i2c_client *client, int mode);
+void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2);
 
 #endif /* MSP3400_H */
index 41715ca..eb3b318 100644 (file)
@@ -1,11 +1,11 @@
 /*
     mxb - v4l2 driver for the Multimedia eXtension Board
-    
+
     Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
 
     Visit http://www.mihu.de/linux/saa7146/mxb/
     for further details about this card.
-    
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
 
 #define I2C_SAA7111 0x24
 
-#define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0) 
+#define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
 
 /* global variable */
 static int mxb_num = 0;
 
-/* initial frequence the tuner will be tuned to. 
+/* initial frequence the tuner will be tuned to.
    in verden (lower saxony, germany) 4148 is a
    channel called "phoenix" */
 static int freq = 4148;
@@ -55,7 +55,7 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 enum { TUNER, AUX1, AUX3, AUX3_YC };
 
 static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
-       { TUNER,        "Tuner",                V4L2_INPUT_TYPE_TUNER,  1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, 
+       { TUNER,        "Tuner",                V4L2_INPUT_TYPE_TUNER,  1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
        { AUX1,         "AUX1",                 V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
        { AUX3,         "AUX3 Composite",       V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
        { AUX3_YC,      "AUX3 S-Video",         V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
@@ -66,7 +66,7 @@ static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
 static struct {
        int hps_source;
        int hps_sync;
-} input_port_selection[MXB_INPUTS] = {         
+} input_port_selection[MXB_INPUTS] = {
        { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
        { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
        { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
@@ -81,7 +81,7 @@ static int video_audio_connect[MXB_INPUTS] =
 /* these are the necessary input-output-pins for bringing one audio source
 (see above) to the CD-output */
 static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
-               { 
+               {
                {{1,1,0},{1,1,0}},      /* Tuner */
                {{5,1,0},{6,1,0}},      /* AUX 1 */
                {{4,1,0},{6,1,0}},      /* AUX 2 */
@@ -122,8 +122,8 @@ static struct saa7146_extension_ioctls ioctls[] = {
        { VIDIOC_S_FREQUENCY,   SAA7146_EXCLUSIVE },
        { VIDIOC_G_AUDIO,       SAA7146_EXCLUSIVE },
        { VIDIOC_S_AUDIO,       SAA7146_EXCLUSIVE },
-       { MXB_S_AUDIO_CD,       SAA7146_EXCLUSIVE },    /* custom control */    
-       { MXB_S_AUDIO_LINE,     SAA7146_EXCLUSIVE },    /* custom control */    
+       { MXB_S_AUDIO_CD,       SAA7146_EXCLUSIVE },    /* custom control */
+       { MXB_S_AUDIO_LINE,     SAA7146_EXCLUSIVE },    /* custom control */
        { 0,                    0 }
 };
 
@@ -132,7 +132,7 @@ struct mxb
        struct video_device     *video_dev;
        struct video_device     *vbi_dev;
 
-       struct i2c_adapter      i2c_adapter;    
+       struct i2c_adapter      i2c_adapter;
 
        struct i2c_client*      saa7111a;
        struct i2c_client*      tda9840;
@@ -200,15 +200,15 @@ static int mxb_probe(struct saa7146_dev* dev)
                client = list_entry(item, struct i2c_client, list);
                if( I2C_TEA6420_1 == client->addr )
                        mxb->tea6420_1 = client;
-               if( I2C_TEA6420_2 == client->addr ) 
+               if( I2C_TEA6420_2 == client->addr )
                        mxb->tea6420_2 = client;
-               if( I2C_TEA6415C_2 == client->addr ) 
+               if( I2C_TEA6415C_2 == client->addr )
                        mxb->tea6415c = client;
-               if( I2C_TDA9840 == client->addr ) 
+               if( I2C_TDA9840 == client->addr )
                        mxb->tda9840 = client;
                if( I2C_SAA7111 == client->addr )
                        mxb->saa7111a = client;
-               if( 0x60 == client->addr ) 
+               if( 0x60 == client->addr )
                        mxb->tuner = client;
        }
 
@@ -222,7 +222,7 @@ static int mxb_probe(struct saa7146_dev* dev)
                return -ENODEV;
        }
 
-       /* all devices are present, probe was successful */     
+       /* all devices are present, probe was successful */
 
        /* we store the pointer in our private data field */
        dev->ext_priv = mxb;
@@ -230,7 +230,7 @@ static int mxb_probe(struct saa7146_dev* dev)
        return 0;
 }
 
-/* some init data for the saa7740, the so-called 'sound arena module'. 
+/* some init data for the saa7740, the so-called 'sound arena module'.
    there are no specs available, so we simply use some init values */
 static struct {
        int     length;
@@ -330,7 +330,7 @@ static int mxb_init_done(struct saa7146_dev* dev)
        v4l2_std_id std = V4L2_STD_PAL_BG;
 
        int i = 0, err = 0;
-       struct  tea6415c_multiplex vm;  
+       struct  tea6415c_multiplex vm;
 
        /* select video mode in saa7111a */
        i = VIDEO_MODE_PAL;
@@ -380,16 +380,16 @@ static int mxb_init_done(struct saa7146_dev* dev)
        vm.in  = 3;
        vm.out = 13;
        mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
-                               
+
        /* the rest for mxb */
        mxb->cur_input = 0;
        mxb->cur_mute = 1;
 
        mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
        mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
-                       
+
        /* check if the saa7740 (aka 'sound arena module') is present
-          on the mxb. if so, we must initialize it. due to lack of 
+          on the mxb. if so, we must initialize it. due to lack of
           informations about the saa7740, the values were reverse
           engineered. */
        msg.addr = 0x1b;
@@ -409,7 +409,7 @@ static int mxb_init_done(struct saa7146_dev* dev)
                                break;
                        }
 
-                       msg.len = mxb_saa7740_init[i].length;           
+                       msg.len = mxb_saa7740_init[i].length;
                        msg.buf = &mxb_saa7740_init[i].data[0];
                        if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
                                DEB_D(("failed to initialize 'sound arena module'.\n"));
@@ -418,12 +418,12 @@ static int mxb_init_done(struct saa7146_dev* dev)
                }
                INFO(("'sound arena module' detected.\n"));
        }
-err:   
+err:
        /* the rest for saa7146: you should definitely set some basic values
           for the input-port handling of the saa7146. */
 
        /* ext->saa has been filled by the core driver */
-          
+
        /* some stuff is done via variables */
        saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
 
@@ -431,7 +431,7 @@ err:
 
        /* this is ugly, but because of the fact that this is completely
           hardware dependend, it should be done directly... */
-       saa7146_write(dev, DD1_STREAM_B,        0x00000000);
+       saa7146_write(dev, DD1_STREAM_B,        0x00000000);
        saa7146_write(dev, DD1_INIT,            0x02000200);
        saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
@@ -453,7 +453,7 @@ static struct saa7146_ext_vv vv_data;
 static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
        struct mxb* mxb = (struct mxb*)dev->ext_priv;
-       
+
        DEB_EE(("dev:%p\n",dev));
 
        /* checking for i2c-devices can be omitted here, because we
@@ -464,7 +464,7 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
                ERR(("cannot register capture v4l2 device. skipping.\n"));
                return -1;
        }
-       
+
        /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
        if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
                if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
@@ -513,17 +513,17 @@ static int mxb_detach(struct saa7146_dev* dev)
        return 0;
 }
 
-static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) 
+static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
        struct saa7146_dev *dev = fh->dev;
        struct mxb* mxb = (struct mxb*)dev->ext_priv;
-       struct saa7146_vv *vv = dev->vv_data; 
-       
+       struct saa7146_vv *vv = dev->vv_data;
+
        switch(cmd) {
        case VIDIOC_ENUMINPUT:
        {
                struct v4l2_input *i = arg;
-               
+
                DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
                if( i->index < 0 || i->index >= MXB_INPUTS) {
                        return -EINVAL;
@@ -559,11 +559,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                                break;
                        }
                }
-               
+
                if( i < 0 ) {
                        return -EAGAIN;
                }
-                       
+
                switch (vc->id ) {
                        case V4L2_CID_AUDIO_MUTE: {
                                vc->value = mxb->cur_mute;
@@ -571,7 +571,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                                return 0;
                        }
                }
-               
+
                DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
                return 0;
        }
@@ -580,17 +580,17 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        {
                struct  v4l2_control    *vc = arg;
                int i = 0;
-               
+
                for (i = MAXCONTROLS - 1; i >= 0; i--) {
                        if (mxb_controls[i].id == vc->id) {
                                break;
                        }
                }
-               
+
                if( i < 0 ) {
                        return -EAGAIN;
                }
-               
+
                switch (vc->id ) {
                        case V4L2_CID_AUDIO_MUTE: {
                                mxb->cur_mute = vc->value;
@@ -614,12 +614,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                *input = mxb->cur_input;
 
                DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
-               return 0;               
-       }       
+               return 0;
+       }
        case VIDIOC_S_INPUT:
        {
                int input = *(int *)arg;
-               struct  tea6415c_multiplex vm;  
+               struct  tea6415c_multiplex vm;
                int i = 0;
 
                DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
@@ -627,34 +627,34 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                if (input < 0 || input >= MXB_INPUTS) {
                        return -EINVAL;
                }
-               
+
                /* fixme: locke das setzen des inputs mit hilfe des mutexes
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
                video_mux(dev,*i);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                */
-                               
+
                /* fixme: check if streaming capture
                if ( 0 != dev->streaming ) {
                        DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
                        return -EPERM;
                }
                */
-               
+
                mxb->cur_input = input;
-       
+
                saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
-               
+
                /* prepare switching of tea6415c and saa7111a;
                   have a look at the 'background'-file for further informations  */
                switch( input ) {
-                       
+
                        case TUNER:
                        {
                                i = 0;
                                vm.in  = 3;
                                vm.out = 17;
-                                                               
+
                        if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
                                        printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
                                        return -EFAULT;
@@ -662,7 +662,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                                /* connect tuner-output always to multicable */
                                vm.in  = 3;
                                vm.out = 13;
-                               break;                          
+                               break;
                        }
                        case AUX3_YC:
                        {
@@ -703,11 +703,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                                break;
                        }
                }
-                               
+
                /* switch video in saa7111a */
                if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
                        printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
-               }                       
+               }
 
                /* switch the audio-source only if necessary */
                if( 0 == mxb->cur_mute ) {
@@ -738,11 +738,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                t->rangehigh = 13684;   /* 855.25 MHz / 62.5 kHz = 13684 */
                /* FIXME: add the real signal strength here */
                t->signal = 0xffff;
-               t->afc = 0;             
+               t->afc = 0;
 
                mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
                t->audmode = mxb->cur_mode;
-               
+
                if( byte < 0 ) {
                        t->rxsubchans  = V4L2_TUNER_SUB_MONO;
                } else {
@@ -777,12 +777,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                struct v4l2_tuner *t = arg;
                int result = 0;
                int byte = 0;
-               
+
                if( 0 != t->index ) {
                        DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
                        return -EINVAL;
                }
-       
+
                switch(t->audmode) {
                        case V4L2_TUNER_MODE_STEREO: {
                                mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
@@ -813,7 +813,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
                        printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
                }
-                               
+
                return 0;
        }
        case VIDIOC_G_FREQUENCY:
@@ -839,7 +839,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 
                if (V4L2_TUNER_ANALOG_TV != f->type)
                        return -EINVAL;
-               
+
                if(0 != mxb->cur_input) {
                        DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
                        return -EINVAL;
@@ -848,7 +848,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                mxb->cur_freq = *f;
                DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
 
-               /* tune in desired frequency */                 
+               /* tune in desired frequency */
                mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
 
                /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
@@ -861,12 +861,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        case MXB_S_AUDIO_CD:
        {
                int i = *(int*)arg;
-                               
+
                if( i < 0 || i >= MXB_AUDIOS ) {
                        DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
                        return -EINVAL;
                }
-               
+
                DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
 
                mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
@@ -877,12 +877,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
        case MXB_S_AUDIO_LINE:
        {
                int i = *(int*)arg;
-                               
+
                if( i < 0 || i >= MXB_AUDIOS ) {
                        DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
                        return -EINVAL;
                }
-               
+
                DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
                mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
                mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
@@ -894,13 +894,13 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                struct v4l2_audio *a = arg;
 
                if( a->index < 0 || a->index > MXB_INPUTS ) {
-                       DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
+                       DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
                        return -EINVAL;
                }
-               
-               DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
+
+               DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
                memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
-               
+
                return 0;
        }
        case VIDIOC_S_AUDIO:
@@ -908,7 +908,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
                struct v4l2_audio *a = arg;
                DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
                return 0;
-       }       
+       }
        default:
 /*
                DEB2(printk("does not handle this ioctl.\n"));
@@ -928,7 +928,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
                v4l2_std_id std = V4L2_STD_PAL_I;
                DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
                /* set the 7146 gpio register -- I don't know what this does exactly */
-               saa7146_write(dev, GPIO_CTRL, 0x00404050);
+               saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* unset the 7111 gpio register -- I don't know what this does exactly */
                mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
                mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
@@ -936,7 +936,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
                v4l2_std_id std = V4L2_STD_PAL_BG;
                DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
                /* set the 7146 gpio register -- I don't know what this does exactly */
-               saa7146_write(dev, GPIO_CTRL, 0x00404050);
+               saa7146_write(dev, GPIO_CTRL, 0x00404050);
                /* set the 7111 gpio register -- I don't know what this does exactly */
                mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
                mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
@@ -969,8 +969,8 @@ static struct saa7146_standard standard[] = {
 };
 
 static struct saa7146_pci_extension_data mxb = {
-        .ext_priv = "Multimedia eXtension Board",
-        .ext = &extension,
+       .ext_priv = "Multimedia eXtension Board",
+       .ext = &extension,
 };
 
 static struct pci_device_id pci_tbl[] = {
@@ -992,7 +992,7 @@ static struct saa7146_ext_vv vv_data = {
        .capabilities   = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
        .stds           = &standard[0],
        .num_stds       = sizeof(standard)/sizeof(struct saa7146_standard),
-       .std_callback   = &std_callback, 
+       .std_callback   = &std_callback,
        .ioctls         = &ioctls[0],
        .ioctl          = mxb_ioctl,
 };
@@ -1000,7 +1000,7 @@ static struct saa7146_ext_vv vv_data = {
 static struct saa7146_extension extension = {
        .name           = MXB_IDENTIFIER,
        .flags          = SAA7146_USE_I2C_IRQ,
-       
+
        .pci_tbl        = &pci_tbl[0],
        .module         = THIS_MODULE,
 
@@ -1010,7 +1010,7 @@ static struct saa7146_extension extension = {
 
        .irq_mask       = 0,
        .irq_func       = NULL,
-};     
+};
 
 static int __init mxb_init_module(void)
 {
@@ -1018,7 +1018,7 @@ static int __init mxb_init_module(void)
                DEB_S(("failed to register extension.\n"));
                return -ENODEV;
        }
-       
+
        return 0;
 }
 
index 2332ed5..400a57b 100644 (file)
@@ -38,5 +38,5 @@ static struct v4l2_audio mxb_audios[MXB_AUDIOS] = {
                .name   = "CD-ROM (X10)",
                .capability = V4L2_AUDCAP_STEREO,
        }
-};     
+};
 #endif
index f3fc361..15fd85a 100644 (file)
@@ -48,7 +48,7 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "planb.h"
 #include "saa7196.h"
@@ -329,12 +329,12 @@ static volatile struct dbdma_cmd *cmd_geo_setup(
 
 static inline void planb_lock(struct planb *pb)
 {
-       down(&pb->lock);
+       mutex_lock(&pb->lock);
 }
 
 static inline void planb_unlock(struct planb *pb)
 {
-       up(&pb->lock);
+       mutex_unlock(&pb->lock);
 }
 
 /***************/
@@ -2067,7 +2067,7 @@ static int init_planb(struct planb *pb)
 #endif
        pb->tab_size = PLANB_MAXLINES + 40;
        pb->suspend = 0;
-       init_MUTEX(&pb->lock);
+       mutex_init(&pb->lock);
        pb->ch1_cmd = 0;
        pb->ch2_cmd = 0;
        pb->mask = 0;
index 8a0faad..79b6b56 100644 (file)
@@ -174,7 +174,7 @@ struct planb {
        int     user;
        unsigned int tab_size;
        int     maxlines;
-       struct semaphore lock;
+       struct mutex lock;
        unsigned int    irq;                    /* interrupt number */
        volatile unsigned int intr_mask;
 
index 9e64486..05ca559 100644 (file)
@@ -30,6 +30,8 @@
 #include <asm/io.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 
@@ -44,7 +46,7 @@ struct pms_device
        struct video_picture picture;
        int height;
        int width;
-       struct semaphore lock;
+       struct mutex lock;
 };
 
 struct i2c_info
@@ -724,10 +726,10 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
                        struct video_channel *v = arg;
                        if(v->channel<0 || v->channel>3)
                                return -EINVAL;
-                       down(&pd->lock);
+                       mutex_lock(&pd->lock);
                        pms_videosource(v->channel&1);
                        pms_vcrinput(v->channel>>1);
-                       up(&pd->lock);
+                       mutex_unlock(&pd->lock);
                        return 0;
                }
                case VIDIOCGTUNER:
@@ -761,7 +763,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
                        struct video_tuner *v = arg;
                        if(v->tuner)
                                return -EINVAL;
-                       down(&pd->lock);
+                       mutex_lock(&pd->lock);
                        switch(v->mode)
                        {
                                case VIDEO_MODE_AUTO:
@@ -785,10 +787,10 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
                                        pms_format(2);
                                        break;
                                default:
-                                       up(&pd->lock);
+                                       mutex_unlock(&pd->lock);
                                        return -EINVAL;
                        }
-                       up(&pd->lock);
+                       mutex_unlock(&pd->lock);
                        return 0;
                }
                case VIDIOCGPICT:
@@ -809,12 +811,12 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
                         *      Now load the card.
                         */
 
-                       down(&pd->lock);
+                       mutex_lock(&pd->lock);
                        pms_brightness(p->brightness>>8);
                        pms_hue(p->hue>>8);
                        pms_colour(p->colour>>8);
                        pms_contrast(p->contrast>>8);   
-                       up(&pd->lock);
+                       mutex_unlock(&pd->lock);
                        return 0;
                }
                case VIDIOCSWIN:
@@ -830,9 +832,9 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
                                return -EINVAL;
                        pd->width=vw->width;
                        pd->height=vw->height;
-                       down(&pd->lock);
+                       mutex_lock(&pd->lock);
                        pms_resolution(pd->width, pd->height);
-                       up(&pd->lock);                  /* Ok we figured out what to use from our wide choice */
+                       mutex_unlock(&pd->lock);                        /* Ok we figured out what to use from our wide choice */
                        return 0;
                }
                case VIDIOCGWIN:
@@ -872,9 +874,9 @@ static ssize_t pms_read(struct file *file, char __user *buf,
        struct pms_device *pd=(struct pms_device *)v;
        int len;
        
-       down(&pd->lock);
+       mutex_lock(&pd->lock);
        len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count);
-       up(&pd->lock);
+       mutex_unlock(&pd->lock);
        return len;
 }
 
@@ -1029,7 +1031,7 @@ static int __init init_pms_cards(void)
                return -ENODEV;
        }
        memcpy(&pms_device, &pms_template, sizeof(pms_template));
-       init_MUTEX(&pms_device.lock);
+       mutex_init(&pms_device.lock);
        pms_device.height=240;
        pms_device.width=320;
        pms_swsense(75);
index 2ce0102..dd830e0 100644 (file)
@@ -46,6 +46,8 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 #include "saa5246a.h"
 
 MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
@@ -57,7 +59,7 @@ struct saa5246a_device
        u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
        int    is_searching[NUM_DAUS];
        struct i2c_client *client;
-       struct semaphore lock;
+       struct mutex lock;
 };
 
 static struct video_device saa_template;       /* Declared near bottom */
@@ -90,7 +92,7 @@ static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind)
                return -ENOMEM;
        }
        strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-       init_MUTEX(&t->lock);
+       mutex_init(&t->lock);
 
        /*
         *      Now create a video4linux device
@@ -719,9 +721,9 @@ static int saa5246a_ioctl(struct inode *inode, struct file *file,
        int err;
 
        cmd = vtx_fix_command(cmd);
-       down(&t->lock);
+       mutex_lock(&t->lock);
        err = video_usercopy(inode, file, cmd, arg, do_saa5246a_ioctl);
-       up(&t->lock);
+       mutex_unlock(&t->lock);
        return err;
 }
 
index 5694eb5..a9f3cf0 100644 (file)
@@ -56,6 +56,8 @@
 #include <linux/i2c.h>
 #include <linux/videotext.h>
 #include <linux/videodev.h>
+#include <linux/mutex.h>
+
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -105,7 +107,7 @@ struct saa5249_device
        int disp_mode;
        int virtual_mode;
        struct i2c_client *client;
-       struct semaphore lock;
+       struct mutex lock;
 };
 
 
@@ -158,7 +160,7 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
                return -ENOMEM;
        }
        strlcpy(client->name, IF_NAME, I2C_NAME_SIZE);
-       init_MUTEX(&t->lock);
+       mutex_init(&t->lock);
        
        /*
         *      Now create a video4linux device
@@ -619,9 +621,9 @@ static int saa5249_ioctl(struct inode *inode, struct file *file,
        int err;
        
        cmd = vtx_fix_command(cmd);
-       down(&t->lock);
+       mutex_lock(&t->lock);
        err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl);
-       up(&t->lock);
+       mutex_unlock(&t->lock);
        return err;
 }
 
index ffd87ce..b184fd0 100644 (file)
@@ -1,4 +1,4 @@
-/* saa7115 - Philips SAA7114/SAA7115 video decoder driver
+/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver
  *
  * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
  * the saa7111 driver by Dave Perks.
@@ -16,6 +16,7 @@
  * (2/17/2003)
  *
  * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
+ * SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -42,8 +43,9 @@
 #include <media/audiochip.h>
 #include <asm/div64.h>
 
-MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
-MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
+MODULE_AUTHOR(  "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
+               "Hans Verkuil, Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
 
 static int debug = 0;
@@ -51,7 +53,10 @@ module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = {
+               0x4a >>1, 0x48 >>1,     /* SAA7113 */
+               0x42 >> 1, 0x40 >> 1,   /* SAA7114 and SAA7115 */
+               I2C_CLIENT_END };
 
 
 I2C_CLIENT_INSMOD;
@@ -101,10 +106,12 @@ static inline int saa7115_read(struct i2c_client *client, u8 reg)
    Hauppauge driver sets. */
 
 static const unsigned char saa7115_init_auto_input[] = {
+               /* Front-End Part */
        0x01, 0x48,             /* white peak control disabled */
        0x03, 0x20,             /* was 0x30. 0x20: long vertical blanking */
        0x04, 0x90,             /* analog gain set to 0 */
        0x05, 0x90,             /* analog gain set to 0 */
+               /* Decoder Part */
        0x06, 0xeb,             /* horiz sync begin = -21 */
        0x07, 0xe0,             /* horiz sync stop = -17 */
        0x0a, 0x80,             /* was 0x88. decoder brightness, 0x80 is itu standard */
@@ -123,6 +130,8 @@ static const unsigned char saa7115_init_auto_input[] = {
        0x1b, 0x42,             /* misc chroma control 0x42 = recommended */
        0x1c, 0xa9,             /* combfilter control 0xA9 = recommended */
        0x1d, 0x01,             /* combfilter control 0x01 = recommended */
+
+               /* Power Device Control */
        0x88, 0xd0,             /* reset device */
        0x88, 0xf0,             /* set device programmed, all in operational mode */
        0x00, 0x00
@@ -338,6 +347,33 @@ static const unsigned char saa7115_cfg_vbi_off[] = {
        0x00, 0x00
 };
 
+static const unsigned char saa7113_init_auto_input[] = {
+       0x01, 0x08,     /* PH7113_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
+       0x02, 0xc2,     /* PH7113_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
+       0x03, 0x30,     /* PH7113_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
+       0x04, 0x00,     /* PH7113_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
+       0x05, 0x00,     /* PH7113_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
+       0x06, 0x89,     /* PH7113_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
+       0x07, 0x0d,     /* PH7113_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
+       0x08, 0x88,     /* PH7113_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
+       0x09, 0x01,     /* PH7113_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
+       0x0a, 0x80,     /* PH7113_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
+       0x0b, 0x47,     /* PH7113_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
+       0x0c, 0x40,     /* PH7113_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
+       0x0d, 0x00,     /* PH7113_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
+       0x0e, 0x01,     /* PH7113_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
+       0x0f, 0x2a,     /* PH7113_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
+       0x10, 0x08,     /* PH7113_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
+       0x11, 0x0c,     /* PH7113_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
+       0x12, 0x07,     /* PH7113_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
+       0x13, 0x00,     /* PH7113_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
+       0x14, 0x00,     /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
+       0x15, 0x00,     /* PH7113_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
+       0x16, 0x00,     /* PH7113_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
+       0x17, 0x00,     /* PH7113_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
+       0x00, 0x00
+};
+
 static const unsigned char saa7115_init_misc[] = {
        0x38, 0x03,             /* audio stuff */
        0x39, 0x10,
@@ -677,10 +713,35 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
                saa7115_writeregs(client, saa7115_cfg_50hz_video);
        }
 
+       /* Register 0E - Bits D6-D4 on NO-AUTO mode
+               (SAA7113 doesn't have auto mode)
+           50 Hz / 625 lines           60 Hz / 525 lines
+       000 PAL BGDHI (4.43Mhz)         NTSC M (3.58MHz)
+       001 NTSC 4.43 (50 Hz)           PAL 4.43 (60 Hz)
+       010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz)
+       011 NTSC N (3.58MHz)            PAL M (3.58MHz)
+       100 reserved                    NTSC-Japan (3.58MHz)
+       */
+       if (state->ident == V4L2_IDENT_SAA7113) {
+               u8 reg =  saa7115_read(client, 0x0e) & 0x8f;
+
+               if (std == V4L2_STD_PAL_M) {
+                       reg|=0x30;
+               } else if (std == V4L2_STD_PAL_N) {
+                       reg|=0x20;
+               } else if (std == V4L2_STD_PAL_60) {
+                       reg|=0x10;
+               } else if (std == V4L2_STD_NTSC_M_JP) {
+                       reg|=0x40;
+               }
+               saa7115_write(client, 0x0e, reg);
+       }
+
+
        state->std = std;
 
        /* restart task B if needed */
-       if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+       if (taskb && state->ident != V4L2_IDENT_SAA7115) {
                saa7115_writeregs(client, saa7115_cfg_vbi_on);
        }
 
@@ -703,7 +764,7 @@ static void saa7115_log_status(struct i2c_client *client)
        int vcr;
 
        v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
-       if (client->name[6] == '4') {
+       if (state->ident != V4L2_IDENT_SAA7115) {
                /* status for the saa7114 */
                reg1f = saa7115_read(client, 0x1f);
                signalOk = (reg1f & 0xc1) == 0x81;
@@ -751,8 +812,8 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
        u8 lcr[24];
        int i, x;
 
-       /* saa7114 doesn't yet support VBI */
-       if (state->ident == V4L2_IDENT_SAA7114)
+       /* saa7113/71144 doesn't yet support VBI */
+       if (state->ident != V4L2_IDENT_SAA7115)
                return;
 
        for (i = 0; i <= 23; i++)
@@ -791,7 +852,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
                                        case 0:
                                                lcr[i] |= 0xf << (4 * x);
                                                break;
-                                       case V4L2_SLICED_TELETEXT_B:
+                                       case V4L2_SLICED_TELETEXT_PAL_B:
                                                lcr[i] |= 1 << (4 * x);
                                                break;
                                        case V4L2_SLICED_CAPTION_525:
@@ -820,7 +881,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
 static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 {
        static u16 lcr2vbi[] = {
-               0, V4L2_SLICED_TELETEXT_B, 0,   /* 1 */
+               0, V4L2_SLICED_TELETEXT_PAL_B, 0,       /* 1 */
                0, V4L2_SLICED_CAPTION_525,     /* 4 */
                V4L2_SLICED_WSS_625, 0,         /* 5 */
                V4L2_SLICED_VPS, 0, 0, 0, 0,    /* 7 */
@@ -985,7 +1046,7 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
        /* decode payloads */
        switch (id2) {
        case 1:
-               vbi->type = V4L2_SLICED_TELETEXT_B;
+               vbi->type = V4L2_SLICED_TELETEXT_PAL_B;
                break;
        case 4:
                if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
@@ -1261,14 +1322,12 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
 
        saa7115_write(client, 0, 5);
        chip_id = saa7115_read(client, 0) & 0x0f;
-       if (chip_id != 4 && chip_id != 5) {
+       if (chip_id <3 && chip_id > 5) {
                v4l_dbg(1, debug, client, "saa7115 not found\n");
                kfree(client);
                return 0;
        }
-       if (chip_id == 4) {
-               snprintf(client->name, sizeof(client->name) - 1, "saa7114");
-       }
+       snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
        v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
 
        state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL);
@@ -1285,13 +1344,27 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
        state->contrast = 64;
        state->hue = 0;
        state->sat = 64;
-       state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
+       switch (chip_id) {
+       case 3:
+               state->ident = V4L2_IDENT_SAA7113;
+               break;
+       case 4:
+               state->ident = V4L2_IDENT_SAA7114;
+               break;
+       default:
+               state->ident = V4L2_IDENT_SAA7115;
+               break;
+       }
+
        state->audclk_freq = 48000;
 
        v4l_dbg(1, debug, client, "writing init values\n");
 
        /* init to 60hz/48khz */
-       saa7115_writeregs(client, saa7115_init_auto_input);
+       if (state->ident==V4L2_IDENT_SAA7113)
+               saa7115_writeregs(client, saa7113_init_auto_input);
+       else
+               saa7115_writeregs(client, saa7115_init_auto_input);
        saa7115_writeregs(client, saa7115_init_misc);
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
        saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
index 7df5e08..64e2c10 100644 (file)
@@ -308,8 +308,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
 
 static int dsp_buffer_free(struct saa7134_dev *dev)
 {
-       if (!dev->dmasound.blksize)
-               BUG();
+       BUG_ON(!dev->dmasound.blksize);
 
        videobuf_dma_free(&dev->dmasound.dma);
 
@@ -611,12 +610,12 @@ static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
        struct saa7134_dev *dev = saa7134->dev;
        int err;
 
-       down(&dev->dmasound.lock);
+       mutex_lock(&dev->dmasound.lock);
 
        dev->dmasound.read_count  = 0;
        dev->dmasound.read_offset = 0;
 
-       up(&dev->dmasound.lock);
+       mutex_unlock(&dev->dmasound.lock);
 
        pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
        if (pcm == NULL)
@@ -934,7 +933,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
 
        chip->irq = dev->pci->irq;
 
-       init_MUTEX(&dev->dmasound.lock);
+       mutex_init(&dev->dmasound.lock);
 
        if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
                goto __nodev;
index 6bc63a4..fdd7f48 100644 (file)
@@ -536,7 +536,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio = {
                        .name = name_radio,
                        .amux = LINE2,
-       },
+               },
        },
        [SAA7134_BOARD_MD7134] = {
                .name           = "Medion 7134",
@@ -640,6 +640,32 @@ struct saa7134_board saa7134_boards[] = {
                        .tv   = 1,
                }},
        },
+       [SAA7134_BOARD_ELSA_700TV] = {
+               .name           = "ELSA EX-VISION 700TV",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_HITACHI_NTSC,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 4,
+                       .amux = LINE2,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 6,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 7,
+                       .amux = LINE1,
+               }},
+               .mute           = {
+                       .name = name_mute,
+                       .amux = TV,
+               },
+       },
        [SAA7134_BOARD_ASUSTeK_TVFM7134] = {
                .name           = "ASUS TV-FM 7134",
                .audio_clock    = 0x00187de7,
@@ -2002,7 +2028,7 @@ struct saa7134_board saa7134_boards[] = {
        [SAA7134_BOARD_FLYTV_DIGIMATRIX] = {
                .name           = "FlyTV mini Asus Digimatrix",
                .audio_clock    = 0x00200000,
-               .tuner_type     = TUNER_LG_NTSC_TALN_MINI,
+               .tuner_type     = TUNER_LG_TALN,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -2598,6 +2624,7 @@ struct saa7134_board saa7134_boards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .gpiomask       = 0x00200000,
+               .mpeg           = SAA7134_MPEG_DVB,
                .inputs         = {{
                        .name = name_tv,        /* Analog broadcast/cable TV */
                        .vmux = 1,
@@ -2623,6 +2650,164 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x000000,       /* GPIO21=Low for FM radio antenna */
                },
        },
+       [SAA7134_BOARD_AVERMEDIA_777] = {
+               .name           = "AverTV DVB-T 777",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_comp1,
+                       .vmux   = 0,
+                       .amux   = LINE1,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE1,
+               }},
+       },
+       [SAA7134_BOARD_FLYDVBT_LR301] = {
+               /* LifeView FlyDVB-T */
+               /* Giampiero Giancipoli <gianci@libero.it> */
+               .name           = "LifeView FlyDVB-T",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs         = {{
+                       .name = name_comp1,     /* Composite input */
+                       .vmux = 3,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,    /* S-Video signal on S-Video input */
+                       .vmux = 8,
+                       .amux = LINE2,
+               }},
+       },
+       [SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331] = {
+               .name           = "ADS Instant TV Duo Cardbus PTV331",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .gpiomask       = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+                       .gpio   = 0x00200000,
+               }},
+       },
+       [SAA7134_BOARD_TEVION_DVBT_220RF] = {
+               .name           = "Tevion/KWorld DVB-T 220RF",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 3,
+                       .amux   = LINE1,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 0,
+                       .amux   = LINE1,
+               }},
+               .radio = {
+                       .name   = name_radio,
+                       .amux   = LINE1,
+               },
+       },
+       [SAA7134_BOARD_KWORLD_ATSC110] = {
+               .name           = "Kworld ATSC110",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TUV1236D,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+               }},
+       },
+       [SAA7134_BOARD_AVERMEDIA_A169_B] = {
+               /* AVerMedia A169  */
+               /* Rickard Osser <ricky@osser.se>  */
+               /* This card has two saa7134 chips on it,
+                  but only one of them is currently working. */
+               .name           = "AVerMedia A169 B",
+               .audio_clock    = 0x02187de7,
+               .tuner_type     = TUNER_LG_TALN,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x0a60000,
+       },
+       [SAA7134_BOARD_AVERMEDIA_A169_B1] = {
+               /* AVerMedia A169 */
+               /* Rickard Osser <ricky@osser.se> */
+               .name           = "AVerMedia A169 B1",
+               .audio_clock    = 0x02187de7,
+               .tuner_type     = TUNER_LG_TALN,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0xca60000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 4,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x04a61000,
+               },{
+                       .name = name_comp2,  /*  Composite SVIDEO (B/W if signal is carried with SVIDEO) */
+                       .vmux = 1,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 9,           /* 9 is correct as S-VIDEO1 according to a169.inf! */
+                       .amux = LINE1,
+               }},
+       },
+       [SAA7134_BOARD_MD7134_BRIDGE_2] = {
+               /* This card has two saa7134 chips on it,
+                  but only one of them is currently working.
+                  The programming for the primary decoder is
+                  in SAA7134_BOARD_MD7134 */
+               .name           = "Medion 7134 Bridge #2",
+               .audio_clock    = 0x00187de7,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2753,6 +2938,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .driver_data  = SAA7134_BOARD_ELSA_500TV,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x1048,
+               .subdevice    = 0x226c,
+               .driver_data  = SAA7134_BOARD_ELSA_700TV,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = PCI_VENDOR_ID_ASUSTEK,
                .subdevice    = 0x4842,
@@ -3094,6 +3285,54 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0x0319,
                .driver_data  = SAA7134_BOARD_FLYDVB_TRIO,
        },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,  /* SAA 7131E */
+               .subvendor    = 0x1461,
+               .subdevice    = 0x2c05,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_777,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x5168,
+               .subdevice    = 0x0301,
+               .driver_data  = SAA7134_BOARD_FLYDVBT_LR301,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0331,
+               .subdevice    = 0x1421,
+               .driver_data  = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x17de,
+               .subdevice    = 0x7201,
+               .driver_data  = SAA7134_BOARD_TEVION_DVBT_220RF,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+               .subvendor    = 0x17de,
+               .subdevice    = 0x7350,
+               .driver_data  = SAA7134_BOARD_KWORLD_ATSC110,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x1461,
+               .subdevice    = 0x7360,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_A169_B,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x1461,
+               .subdevice    = 0x6360,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_A169_B1,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x16be,
+               .subdevice    = 0x0005,
+               .driver_data  = SAA7134_BOARD_MD7134_BRIDGE_2,
+       },{
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3193,13 +3432,15 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_GOTVIEW_7135:
        case SAA7134_BOARD_KWORLD_TERMINATOR:
        case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+       case SAA7134_BOARD_FLYDVBT_LR301:
+       case SAA7134_BOARD_FLYDVBTDUO:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_MD5044:
                printk("%s: seems there are two different versions of the MD5044\n"
-               "%s: (with the same ID) out there.  If sound doesn't work for\n"
-               "%s: you try the audio_clock_override=0x200000 insmod option.\n",
-               dev->name,dev->name,dev->name);
+                      "%s: (with the same ID) out there.  If sound doesn't work for\n"
+                      "%s: you try the audio_clock_override=0x200000 insmod option.\n",
+                      dev->name,dev->name,dev->name);
                break;
        case SAA7134_BOARD_CINERGY400_CARDBUS:
                /* power-up tuner chip */
@@ -3220,6 +3461,10 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
                saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
                break;
+       case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+               saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
+               saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00);
+               break;
        case SAA7134_BOARD_AVERMEDIA_CARDBUS:
                /* power-up tuner chip */
                saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0xffffffff);
@@ -3242,6 +3487,13 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
                dev->has_remote = SAA7134_REMOTE_I2C;
                break;
+       case SAA7134_BOARD_AVERMEDIA_A169_B:
+       case SAA7134_BOARD_MD7134_BRIDGE_2:
+               printk("%s: %s: dual saa713x broadcast decoders\n"
+                      "%s: Sorry, none of the inputs to this chip are supported yet.\n"
+                      "%s: Dual decoder functionality is disabled for now, use the other chip.\n",
+                      dev->name,card(dev).name,dev->name,dev->name);
+               break;
        }
        return 0;
 }
@@ -3362,14 +3614,44 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                }
                break;
        case SAA7134_BOARD_PHILIPS_TIGER:
+       case SAA7134_BOARD_TEVION_DVBT_220RF:
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
-               /* this is a hybrid board, initialize to analog mode */
+               /* this is a hybrid board, initialize to analog mode
+                * and configure firmware eeprom address
+                */
                {
                u8 data[] = { 0x3c, 0x33, 0x68};
                struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
                i2c_transfer(&dev->i2c_adap, &msg, 1);
                }
                break;
+       case SAA7134_BOARD_FLYDVB_TRIO:
+               {
+               u8 data[] = { 0x3c, 0x33, 0x62};
+               struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)};
+               i2c_transfer(&dev->i2c_adap, &msg, 1);
+               }
+               break;
+       case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+               /* make the tda10046 find its eeprom */
+               {
+               u8 data[] = { 0x3c, 0x33, 0x62};
+               struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+               i2c_transfer(&dev->i2c_adap, &msg, 1);
+               }
+               break;
+       case SAA7134_BOARD_KWORLD_ATSC110:
+               {
+                       /* enable tuner */
+                       int i;
+                       static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+                       dev->i2c_client.addr = 0x0a;
+                       for (i = 0; i < 5; i++)
+                               if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2))
+                                       printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
+                                              dev->name, i);
+               }
+               break;
        }
        return 0;
 }
index 028904b..58e568d 100644 (file)
@@ -66,6 +66,11 @@ static unsigned int latency = UNSET;
 module_param(latency, int, 0444);
 MODULE_PARM_DESC(latency,"pci latency timer");
 
+int saa7134_no_overlay=-1;
+module_param_named(no_overlay, saa7134_no_overlay, int, 0444);
+MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
+               " [some VIA/SIS chipsets are known to have problem with overlay]");
+
 static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
@@ -251,8 +256,7 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
 
 void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf)
 {
-       if (in_interrupt())
-               BUG();
+       BUG_ON(in_interrupt());
 
        videobuf_waiton(&buf->vb,0,0);
        videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma);
@@ -613,7 +617,7 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
 
        saa_writel(SAA7134_IRQ1, 0);
        saa_writel(SAA7134_IRQ2, 0);
-       init_MUTEX(&dev->lock);
+       mutex_init(&dev->lock);
        spin_lock_init(&dev->slock);
 
        saa7134_track_gpio(dev,"pre-init");
@@ -835,6 +839,22 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
                        latency = 0x0A;
                }
 #endif
+               if (pci_pci_problems & PCIPCI_FAIL) {
+                       printk(KERN_INFO "%s: quirk: this driver and your "
+                                       "chipset may not work together"
+                                       " in overlay mode.\n",dev->name);
+                       if (!saa7134_no_overlay) {
+                               printk(KERN_INFO "%s: quirk: overlay "
+                                               "mode will be disabled.\n",
+                                               dev->name);
+                               saa7134_no_overlay = 1;
+                       } else {
+                               printk(KERN_INFO "%s: quirk: overlay "
+                                               "mode will be forced. Use this"
+                                               " option at your own risk.\n",
+                                               dev->name);
+                       }
+               }
        }
        if (UNSET != latency) {
                printk(KERN_INFO "%s: setting pci latency timer to %d\n",
@@ -937,6 +957,11 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        v4l2_prio_init(&dev->prio);
 
        /* register v4l devices */
+       if (saa7134_no_overlay <= 0) {
+               saa7134_video_template.type |= VID_TYPE_OVERLAY;
+       } else {
+               printk("bttv: Overlay support disabled.\n");
+       }
        dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
        err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
                                    video_nr[dev->nr]);
index 9db8e13..86cfdb8 100644 (file)
@@ -32,6 +32,7 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 #include <media/v4l2-common.h>
+#include "dvb-pll.h"
 
 #ifdef HAVE_MT352
 # include "mt352.h"
@@ -42,7 +43,6 @@
 #endif
 #ifdef HAVE_NXT200X
 # include "nxt200x.h"
-# include "dvb-pll.h"
 #endif
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -114,6 +114,24 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe)
        return 0;
 }
 
+static int mt352_aver777_init(struct dvb_frontend* fe)
+{
+       static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x2d };
+       static u8 reset []         = { RESET,      0x80 };
+       static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+       static u8 agc_cfg []       = { AGC_TARGET, 0x28, 0xa0 };
+       static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+       mt352_write(fe, clock_config,   sizeof(clock_config));
+       udelay(200);
+       mt352_write(fe, reset,          sizeof(reset));
+       mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+       mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+       mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+       return 0;
+}
+
 static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
                                  struct dvb_frontend_parameters* params,
                                  u8* pllbuf)
@@ -146,6 +164,15 @@ static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
        return 0;
 }
 
+static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf)
+{
+       pllbuf[0] = 0xc2;
+       dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
+                         params->frequency,
+                         params->u.ofdm.bandwidth);
+       return 0;
+}
+
 static struct mt352_config pinnacle_300i = {
        .demod_address = 0x3c >> 1,
        .adc_clock     = 20333,
@@ -154,6 +181,12 @@ static struct mt352_config pinnacle_300i = {
        .demod_init    = mt352_pinnacle_init,
        .pll_set       = mt352_pinnacle_pll_set,
 };
+
+static struct mt352_config avermedia_777 = {
+       .demod_address = 0xf,
+       .demod_init    = mt352_aver777_init,
+       .pll_set       = mt352_aver777_pll_set,
+};
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -781,7 +814,7 @@ static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa
        tda8290_msg.buf = tda8290_open;
        i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
        return ret;
-};
+}
 
 static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
 {
@@ -817,6 +850,110 @@ static struct tda1004x_config philips_tiger_config = {
        .request_firmware = NULL,
 };
 
+/* ------------------------------------------------------------------ */
+
+static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       int ret;
+
+       ret = philips_tda827xa_pll_set(0x60, fe, params);
+       return ret;
+}
+
+static int lifeview_trio_dvb_mode(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static void lifeview_trio_analog_mode(struct dvb_frontend *fe)
+{
+       philips_tda827xa_pll_sleep(0x60, fe);
+}
+
+static struct tda1004x_config lifeview_trio_config = {
+       .demod_address = 0x09,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X_GPL,
+       .if_freq       = TDA10046_FREQ_045,
+       .pll_init      = lifeview_trio_dvb_mode,
+       .pll_set       = lifeview_trio_pll_set,
+       .pll_sleep     = lifeview_trio_analog_mode,
+       .request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       int ret;
+
+       ret = philips_tda827xa_pll_set(0x61, fe, params);
+       return ret;
+}
+
+static int ads_duo_dvb_mode(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       /* route TDA8275a AGC input to the channel decoder */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60);
+       return 0;
+}
+
+static void ads_duo_analog_mode(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       /* route TDA8275a AGC input to the analog IF chip*/
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
+       philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config ads_tech_duo_config = {
+       .demod_address = 0x08,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X_GPL,
+       .if_freq       = TDA10046_FREQ_045,
+       .pll_init      = ads_duo_dvb_mode,
+       .pll_set       = ads_duo_pll_set,
+       .pll_sleep     = ads_duo_analog_mode,
+       .request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       int ret;
+       ret = philips_tda827xa_pll_set(0x60, fe, params);
+       return ret;
+}
+
+static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe)
+{
+       philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config tevion_dvbt220rf_config = {
+       .demod_address = 0x08,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X,
+       .if_freq       = TDA10046_FREQ_045,
+       .pll_init      = tevion_dvb220rf_pll_init,
+       .pll_set       = tevion_dvb220rf_pll_set,
+       .pll_sleep     = tevion_dvb220rf_pll_sleep,
+       .request_firmware = NULL,
+};
+
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -827,6 +964,22 @@ static struct nxt200x_config avertvhda180 = {
        .pll_address      = 0x61,
        .pll_desc         = &dvb_pll_tdhu2,
 };
+
+static int nxt200x_set_pll_input(u8 *buf, int input)
+{
+       if (input)
+               buf[3] |= 0x08;
+       else
+               buf[3] &= ~0x08;
+       return 0;
+}
+
+static struct nxt200x_config kworldatsc110 = {
+       .demod_address    = 0x0a,
+       .pll_address      = 0x61,
+       .pll_desc         = &dvb_pll_tuv1236d,
+       .set_pll_input    = nxt200x_set_pll_input,
+};
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -851,6 +1004,12 @@ static int dvb_init(struct saa7134_dev *dev)
                dev->dvb.frontend = mt352_attach(&pinnacle_300i,
                                                 &dev->i2c_adap);
                break;
+
+       case SAA7134_BOARD_AVERMEDIA_777:
+               printk("%s: avertv 777 dvb setup\n",dev->name);
+               dev->dvb.frontend = mt352_attach(&avermedia_777,
+                                                &dev->i2c_adap);
+               break;
 #endif
 #ifdef HAVE_TDA1004X
        case SAA7134_BOARD_MD7134:
@@ -889,11 +1048,30 @@ static int dvb_init(struct saa7134_dev *dev)
                dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
                                                    &dev->i2c_adap);
                break;
+       case SAA7134_BOARD_FLYDVBT_LR301:
+               dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
+                                                   &dev->i2c_adap);
+               break;
+       case SAA7134_BOARD_FLYDVB_TRIO:
+               dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
+                                                   &dev->i2c_adap);
+               break;
+       case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+               dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
+                                                   &dev->i2c_adap);
+               break;
+       case SAA7134_BOARD_TEVION_DVBT_220RF:
+               dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
+                                                   &dev->i2c_adap);
+               break;
 #endif
 #ifdef HAVE_NXT200X
        case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
                dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
                break;
+       case SAA7134_BOARD_KWORLD_ATSC110:
+               dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+               break;
 #endif
        default:
                printk("%s: Huh? unknown DVB card?\n",dev->name);
index bd4c389..1d972ed 100644 (file)
@@ -89,7 +89,7 @@ static int ts_open(struct inode *inode, struct file *file)
 
        dprintk("open minor=%d\n",minor);
        err = -EBUSY;
-       if (down_trylock(&dev->empress_tsq.lock))
+       if (!mutex_trylock(&dev->empress_tsq.lock))
                goto done;
        if (dev->empress_users)
                goto done_up;
@@ -99,7 +99,7 @@ static int ts_open(struct inode *inode, struct file *file)
        err = 0;
 
 done_up:
-       up(&dev->empress_tsq.lock);
+       mutex_unlock(&dev->empress_tsq.lock);
 done:
        return err;
 }
@@ -110,7 +110,7 @@ static int ts_release(struct inode *inode, struct file *file)
 
        if (dev->empress_tsq.streaming)
                videobuf_streamoff(&dev->empress_tsq);
-       down(&dev->empress_tsq.lock);
+       mutex_lock(&dev->empress_tsq.lock);
        if (dev->empress_tsq.reading)
                videobuf_read_stop(&dev->empress_tsq);
        videobuf_mmap_free(&dev->empress_tsq);
@@ -119,7 +119,7 @@ static int ts_release(struct inode *inode, struct file *file)
        /* stop the encoder */
        ts_reset_encoder(dev);
 
-       up(&dev->empress_tsq.lock);
+       mutex_unlock(&dev->empress_tsq.lock);
        return 0;
 }
 
index 82d28cb..1426e4c 100644 (file)
@@ -42,485 +42,6 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
-/* ---------------------------------------------------------------------- */
-
-static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
-       [   15 ] = KEY_KP0,
-       [    3 ] = KEY_KP1,
-       [    4 ] = KEY_KP2,
-       [    5 ] = KEY_KP3,
-       [    7 ] = KEY_KP4,
-       [    8 ] = KEY_KP5,
-       [    9 ] = KEY_KP6,
-       [   11 ] = KEY_KP7,
-       [   12 ] = KEY_KP8,
-       [   13 ] = KEY_KP9,
-
-       [   14 ] = KEY_MODE,         // Air/Cable
-       [   17 ] = KEY_VIDEO,        // Video
-       [   21 ] = KEY_AUDIO,        // Audio
-       [    0 ] = KEY_POWER,        // Power
-       [   24 ] = KEY_TUNER,        // AV Source
-       [    2 ] = KEY_ZOOM,         // Fullscreen
-       [   26 ] = KEY_LANGUAGE,     // Stereo
-       [   27 ] = KEY_MUTE,         // Mute
-       [   20 ] = KEY_VOLUMEUP,     // Volume +
-       [   23 ] = KEY_VOLUMEDOWN,   // Volume -
-       [   18 ] = KEY_CHANNELUP,    // Channel +
-       [   19 ] = KEY_CHANNELDOWN,  // Channel -
-       [    6 ] = KEY_AGAIN,        // Recall
-       [   16 ] = KEY_ENTER,      // Enter
-};
-
-
-static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
-       [    0 ] = KEY_KP0,
-       [    1 ] = KEY_KP1,
-       [    2 ] = KEY_KP2,
-       [    3 ] = KEY_KP3,
-       [    4 ] = KEY_KP4,
-       [    5 ] = KEY_KP5,
-       [    6 ] = KEY_KP6,
-       [    7 ] = KEY_KP7,
-       [    8 ] = KEY_KP8,
-       [    9 ] = KEY_KP9,
-
-       [ 0x0a ] = KEY_POWER,
-       [ 0x0b ] = KEY_PROG1,           // app
-       [ 0x0c ] = KEY_ZOOM,            // zoom/fullscreen
-       [ 0x0d ] = KEY_CHANNELUP,       // channel
-       [ 0x0e ] = KEY_CHANNELDOWN,     // channel-
-       [ 0x0f ] = KEY_VOLUMEUP,
-       [ 0x10 ] = KEY_VOLUMEDOWN,
-       [ 0x11 ] = KEY_TUNER,           // AV
-       [ 0x12 ] = KEY_NUMLOCK,         // -/--
-       [ 0x13 ] = KEY_AUDIO,           // audio
-       [ 0x14 ] = KEY_MUTE,
-       [ 0x15 ] = KEY_UP,
-       [ 0x16 ] = KEY_DOWN,
-       [ 0x17 ] = KEY_LEFT,
-       [ 0x18 ] = KEY_RIGHT,
-       [ 0x19 ] = BTN_LEFT,
-       [ 0x1a ] = BTN_RIGHT,
-       [ 0x1b ] = KEY_WWW,             // text
-       [ 0x1c ] = KEY_REWIND,
-       [ 0x1d ] = KEY_FORWARD,
-       [ 0x1e ] = KEY_RECORD,
-       [ 0x1f ] = KEY_PLAY,
-       [ 0x20 ] = KEY_PREVIOUSSONG,
-       [ 0x21 ] = KEY_NEXTSONG,
-       [ 0x22 ] = KEY_PAUSE,
-       [ 0x23 ] = KEY_STOP,
-};
-
-/* Alfons Geser <a.geser@cox.net>
- * updates from Job D. R. Borges <jobdrb@ig.com.br> */
-static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
-       [ 18 ] = KEY_POWER,
-       [  1 ] = KEY_TV,             // DVR
-       [ 21 ] = KEY_DVD,            // DVD
-       [ 23 ] = KEY_AUDIO,          // music
-                                    // DVR mode / DVD mode / music mode
-
-       [ 27 ] = KEY_MUTE,           // mute
-       [  2 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
-       [ 30 ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
-       [ 22 ] = KEY_ZOOM,           // full screen
-       [ 28 ] = KEY_VIDEO,          // video source / eject / delall
-       [ 29 ] = KEY_RESTART,        // playback / angle / del
-       [ 47 ] = KEY_SEARCH,         // scan / menu / playlist
-       [ 48 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
-
-       [ 49 ] = KEY_HELP,           // help
-       [ 50 ] = KEY_MODE,           // num/memo
-       [ 51 ] = KEY_ESC,            // cancel
-
-       [ 12 ] = KEY_UP,             // up
-       [ 16 ] = KEY_DOWN,           // down
-       [  8 ] = KEY_LEFT,           // left
-       [  4 ] = KEY_RIGHT,          // right
-       [  3 ] = KEY_SELECT,         // select
-
-       [ 31 ] = KEY_REWIND,         // rewind
-       [ 32 ] = KEY_PLAYPAUSE,      // play/pause
-       [ 41 ] = KEY_FORWARD,        // forward
-       [ 20 ] = KEY_AGAIN,          // repeat
-       [ 43 ] = KEY_RECORD,         // recording
-       [ 44 ] = KEY_STOP,           // stop
-       [ 45 ] = KEY_PLAY,           // play
-       [ 46 ] = KEY_SHUFFLE,        // snapshot / shuffle
-
-       [  0 ] = KEY_KP0,
-       [  5 ] = KEY_KP1,
-       [  6 ] = KEY_KP2,
-       [  7 ] = KEY_KP3,
-       [  9 ] = KEY_KP4,
-       [ 10 ] = KEY_KP5,
-       [ 11 ] = KEY_KP6,
-       [ 13 ] = KEY_KP7,
-       [ 14 ] = KEY_KP8,
-       [ 15 ] = KEY_KP9,
-
-       [ 42 ] = KEY_VOLUMEUP,
-       [ 17 ] = KEY_VOLUMEDOWN,
-       [ 24 ] = KEY_CHANNELUP,      // CH.tracking up
-       [ 25 ] = KEY_CHANNELDOWN,    // CH.tracking down
-
-       [ 19 ] = KEY_KPENTER,        // enter
-       [ 33 ] = KEY_KPDOT,          // . (decimal dot)
-};
-
-static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
-       [ 30 ] = KEY_POWER,             // power
-       [ 28 ] = KEY_SEARCH,            // scan
-       [  7 ] = KEY_SELECT,            // source
-
-       [ 22 ] = KEY_VOLUMEUP,
-       [ 20 ] = KEY_VOLUMEDOWN,
-       [ 31 ] = KEY_CHANNELUP,
-       [ 23 ] = KEY_CHANNELDOWN,
-       [ 24 ] = KEY_MUTE,
-
-       [  2 ] = KEY_KP0,
-       [  1 ] = KEY_KP1,
-       [ 11 ] = KEY_KP2,
-       [ 27 ] = KEY_KP3,
-       [  5 ] = KEY_KP4,
-       [  9 ] = KEY_KP5,
-       [ 21 ] = KEY_KP6,
-       [  6 ] = KEY_KP7,
-       [ 10 ] = KEY_KP8,
-       [ 18 ] = KEY_KP9,
-       [ 16 ] = KEY_KPDOT,
-
-       [  3 ] = KEY_TUNER,             // tv/fm
-       [  4 ] = KEY_REWIND,            // fm tuning left or function left
-       [ 12 ] = KEY_FORWARD,           // fm tuning right or function right
-
-       [  0 ] = KEY_RECORD,
-       [  8 ] = KEY_STOP,
-       [ 17 ] = KEY_PLAY,
-
-       [ 25 ] = KEY_ZOOM,
-       [ 14 ] = KEY_MENU,              // function
-       [ 19 ] = KEY_AGAIN,             // recall
-       [ 29 ] = KEY_RESTART,           // reset
-       [ 26 ] = KEY_SHUFFLE,           // snapshot/shuffle
-
-// FIXME
-       [ 13 ] = KEY_F21,               // mts
-       [ 15 ] = KEY_F22,               // min
-};
-
-/* Alex Hermann <gaaf@gmx.net> */
-static IR_KEYTAB_TYPE md2819_codes[IR_KEYTAB_SIZE] = {
-       [ 40 ] = KEY_KP1,
-       [ 24 ] = KEY_KP2,
-       [ 56 ] = KEY_KP3,
-       [ 36 ] = KEY_KP4,
-       [ 20 ] = KEY_KP5,
-       [ 52 ] = KEY_KP6,
-       [ 44 ] = KEY_KP7,
-       [ 28 ] = KEY_KP8,
-       [ 60 ] = KEY_KP9,
-       [ 34 ] = KEY_KP0,
-
-       [ 32 ] = KEY_TV,                // TV/FM
-       [ 16 ] = KEY_CD,                // CD
-       [ 48 ] = KEY_TEXT,              // TELETEXT
-       [  0 ] = KEY_POWER,             // POWER
-
-       [  8 ] = KEY_VIDEO,             // VIDEO
-       [  4 ] = KEY_AUDIO,             // AUDIO
-       [ 12 ] = KEY_ZOOM,              // FULL SCREEN
-
-       [ 18 ] = KEY_SUBTITLE,          // DISPLAY      - ???
-       [ 50 ] = KEY_REWIND,            // LOOP         - ???
-       [  2 ] = KEY_PRINT,             // PREVIEW      - ???
-
-       [ 42 ] = KEY_SEARCH,            // AUTOSCAN
-       [ 26 ] = KEY_SLEEP,             // FREEZE       - ???
-       [ 58 ] = KEY_SHUFFLE,           // SNAPSHOT     - ???
-       [ 10 ] = KEY_MUTE,              // MUTE
-
-       [ 38 ] = KEY_RECORD,            // RECORD
-       [ 22 ] = KEY_PAUSE,             // PAUSE
-       [ 54 ] = KEY_STOP,              // STOP
-       [  6 ] = KEY_PLAY,              // PLAY
-
-       [ 46 ] = KEY_RED,               // <RED>
-       [ 33 ] = KEY_GREEN,             // <GREEN>
-       [ 14 ] = KEY_YELLOW,            // <YELLOW>
-       [  1 ] = KEY_BLUE,              // <BLUE>
-
-       [ 30 ] = KEY_VOLUMEDOWN,        // VOLUME-
-       [ 62 ] = KEY_VOLUMEUP,          // VOLUME+
-       [ 17 ] = KEY_CHANNELDOWN,       // CHANNEL/PAGE-
-       [ 49 ] = KEY_CHANNELUP          // CHANNEL/PAGE+
-};
-
-static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
-       [ 20 ] = KEY_MUTE,
-       [ 36 ] = KEY_ZOOM,
-
-       [  1 ] = KEY_DVD,
-       [ 35 ] = KEY_RADIO,
-       [  0 ] = KEY_TV,
-
-       [ 10 ] = KEY_REWIND,
-       [  8 ] = KEY_PLAYPAUSE,
-       [ 15 ] = KEY_FORWARD,
-
-       [  2 ] = KEY_PREVIOUS,
-       [  7 ] = KEY_STOP,
-       [  6 ] = KEY_NEXT,
-
-       [ 12 ] = KEY_UP,
-       [ 14 ] = KEY_DOWN,
-       [ 11 ] = KEY_LEFT,
-       [ 13 ] = KEY_RIGHT,
-       [ 17 ] = KEY_OK,
-
-       [  3 ] = KEY_MENU,
-       [  9 ] = KEY_SETUP,
-       [  5 ] = KEY_VIDEO,
-       [ 34 ] = KEY_CHANNEL,
-
-       [ 18 ] = KEY_VOLUMEUP,
-       [ 21 ] = KEY_VOLUMEDOWN,
-       [ 16 ] = KEY_CHANNELUP,
-       [ 19 ] = KEY_CHANNELDOWN,
-
-       [  4 ] = KEY_RECORD,
-
-       [ 22 ] = KEY_KP1,
-       [ 23 ] = KEY_KP2,
-       [ 24 ] = KEY_KP3,
-       [ 25 ] = KEY_KP4,
-       [ 26 ] = KEY_KP5,
-       [ 27 ] = KEY_KP6,
-       [ 28 ] = KEY_KP7,
-       [ 29 ] = KEY_KP8,
-       [ 30 ] = KEY_KP9,
-       [ 31 ] = KEY_KP0,
-
-       [ 32 ] = KEY_LANGUAGE,
-       [ 33 ] = KEY_SLEEP,
-};
-
-/* Michael Tokarev <mjt@tls.msk.ru>
-   http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
-   keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at
-   least, and probably other cards too.
-   The "ascii-art picture" below (in comments, first row
-   is the keycode in hex, and subsequent row(s) shows
-   the button labels (several variants when appropriate)
-   helps to descide which keycodes to assign to the buttons.
- */
-static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
-
-       /*  0x1c            0x12  *
-        * FUNCTION         POWER *
-        *   FM              (|)  *
-        *                        */
-       [ 0x1c ] = KEY_RADIO,   /*XXX*/
-       [ 0x12 ] = KEY_POWER,
-
-       /*  0x01    0x02    0x03  *
-        *   1       2       3    *
-        *                        *
-        *  0x04    0x05    0x06  *
-        *   4       5       6    *
-        *                        *
-        *  0x07    0x08    0x09  *
-        *   7       8       9    *
-        *                        */
-       [ 0x01 ] = KEY_KP1,
-       [ 0x02 ] = KEY_KP2,
-       [ 0x03 ] = KEY_KP3,
-       [ 0x04 ] = KEY_KP4,
-       [ 0x05 ] = KEY_KP5,
-       [ 0x06 ] = KEY_KP6,
-       [ 0x07 ] = KEY_KP7,
-       [ 0x08 ] = KEY_KP8,
-       [ 0x09 ] = KEY_KP9,
-
-       /*  0x0a    0x00    0x17  *
-        * RECALL    0      +100  *
-        *                  PLUS  *
-        *                        */
-       [ 0x0a ] = KEY_AGAIN,   /*XXX KEY_REWIND? */
-       [ 0x00 ] = KEY_KP0,
-       [ 0x17 ] = KEY_DIGITS,  /*XXX*/
-
-       /*  0x14            0x10  *
-        *  MENU            INFO  *
-        *  OSD                   */
-       [ 0x14 ] = KEY_MENU,
-       [ 0x10 ] = KEY_INFO,
-
-       /*          0x0b          *
-        *           Up           *
-        *                        *
-        *  0x18    0x16    0x0c  *
-        *  Left     Ok     Right *
-        *                        *
-        *         0x015          *
-        *         Down           *
-        *                        */
-       [ 0x0b ] = KEY_UP,      /*XXX KEY_SCROLLUP? */
-       [ 0x18 ] = KEY_LEFT,    /*XXX KEY_BACK? */
-       [ 0x16 ] = KEY_OK,      /*XXX KEY_SELECT? KEY_ENTER? */
-       [ 0x0c ] = KEY_RIGHT,   /*XXX KEY_FORWARD? */
-       [ 0x15 ] = KEY_DOWN,    /*XXX KEY_SCROLLDOWN? */
-
-       /*  0x11            0x0d  *
-        *  TV/AV           MODE  *
-        *  SOURCE         STEREO *
-        *                        */
-       [ 0x11 ] = KEY_TV,      /*XXX*/
-       [ 0x0d ] = KEY_MODE,    /*XXX there's no KEY_STEREO */
-
-       /*  0x0f    0x1b    0x1a  *
-        *  AUDIO   Vol+    Chan+ *
-        *        TIMESHIFT???    *
-        *                        *
-        *  0x0e    0x1f    0x1e  *
-        *  SLEEP   Vol-    Chan- *
-        *                        */
-       [ 0x0f ] = KEY_AUDIO,
-       [ 0x1b ] = KEY_VOLUMEUP,
-       [ 0x1a ] = KEY_CHANNELUP,
-       [ 0x0e ] = KEY_SLEEP,   /*XXX maybe KEY_PAUSE */
-       [ 0x1f ] = KEY_VOLUMEDOWN,
-       [ 0x1e ] = KEY_CHANNELDOWN,
-
-       /*         0x13     0x19  *
-        *         MUTE   SNAPSHOT*
-        *                        */
-       [ 0x13 ] = KEY_MUTE,
-       [ 0x19 ] = KEY_RECORD,  /*XXX*/
-
-       // 0x1d unused ?
-};
-
-
-/* Mike Baikov <mike@baikov.com> */
-static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = {
-
-       [ 33 ] = KEY_POWER,
-       [ 105] = KEY_TV,
-       [ 51 ] = KEY_KP0,
-       [ 81 ] = KEY_KP1,
-       [ 49 ] = KEY_KP2,
-       [ 113] = KEY_KP3,
-       [ 59 ] = KEY_KP4,
-       [ 88 ] = KEY_KP5,
-       [ 65 ] = KEY_KP6,
-       [ 72 ] = KEY_KP7,
-       [ 48 ] = KEY_KP8,
-       [ 83 ] = KEY_KP9,
-       [ 115] = KEY_AGAIN, /* LOOP */
-       [ 10 ] = KEY_AUDIO,
-       [ 97 ] = KEY_PRINT, /* PREVIEW */
-       [ 122] = KEY_VIDEO,
-       [ 32 ] = KEY_CHANNELUP,
-       [ 64 ] = KEY_CHANNELDOWN,
-       [ 24 ] = KEY_VOLUMEDOWN,
-       [ 80 ] = KEY_VOLUMEUP,
-       [ 16 ] = KEY_MUTE,
-       [ 74 ] = KEY_SEARCH,
-       [ 123] = KEY_SHUFFLE, /* SNAPSHOT */
-       [ 34 ] = KEY_RECORD,
-       [ 98 ] = KEY_STOP,
-       [ 120] = KEY_PLAY,
-       [ 57 ] = KEY_REWIND,
-       [ 89 ] = KEY_PAUSE,
-       [ 25 ] = KEY_FORWARD,
-       [  9 ] = KEY_ZOOM,
-
-       [ 82 ] = KEY_F21, /* LIVE TIMESHIFT */
-       [ 26 ] = KEY_F22, /* MIN TIMESHIFT */
-       [ 58 ] = KEY_F23, /* TIMESHIFT */
-       [ 112] = KEY_F24, /* NORMAL TIMESHIFT */
-};
-
-static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
-       [ 0x3  ] = KEY_POWER,
-       [ 0x6f ] = KEY_MUTE,
-       [ 0x10 ] = KEY_BACKSPACE,       /* Recall */
-
-       [ 0x11 ] = KEY_KP0,
-       [ 0x4  ] = KEY_KP1,
-       [ 0x5  ] = KEY_KP2,
-       [ 0x6  ] = KEY_KP3,
-       [ 0x8  ] = KEY_KP4,
-       [ 0x9  ] = KEY_KP5,
-       [ 0xa  ] = KEY_KP6,
-       [ 0xc  ] = KEY_KP7,
-       [ 0xd  ] = KEY_KP8,
-       [ 0xe  ] = KEY_KP9,
-       [ 0x12 ] = KEY_KPDOT,           /* 100+ */
-
-       [ 0x7  ] = KEY_VOLUMEUP,
-       [ 0xb  ] = KEY_VOLUMEDOWN,
-       [ 0x1a ] = KEY_KPPLUS,
-       [ 0x18 ] = KEY_KPMINUS,
-       [ 0x15 ] = KEY_UP,
-       [ 0x1d ] = KEY_DOWN,
-       [ 0xf  ] = KEY_CHANNELUP,
-       [ 0x13 ] = KEY_CHANNELDOWN,
-       [ 0x48 ] = KEY_ZOOM,
-
-       [ 0x1b ] = KEY_VIDEO,           /* Video source */
-       [ 0x49 ] = KEY_LANGUAGE,        /* MTS Select */
-       [ 0x19 ] = KEY_SEARCH,          /* Auto Scan */
-
-       [ 0x4b ] = KEY_RECORD,
-       [ 0x46 ] = KEY_PLAY,
-       [ 0x45 ] = KEY_PAUSE,           /* Pause */
-       [ 0x44 ] = KEY_STOP,
-       [ 0x40 ] = KEY_FORWARD,         /* Forward ? */
-       [ 0x42 ] = KEY_REWIND,          /* Backward ? */
-
-};
-
-/* Mapping for the 28 key remote control as seen at
-   http://www.sednacomputer.com/photo/cardbus-tv.jpg
-   Pavel Mihaylov <bin@bash.info> */
-static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = {
-       [    0 ] = KEY_KP0,
-       [    1 ] = KEY_KP1,
-       [    2 ] = KEY_KP2,
-       [    3 ] = KEY_KP3,
-       [    4 ] = KEY_KP4,
-       [    5 ] = KEY_KP5,
-       [    6 ] = KEY_KP6,
-       [    7 ] = KEY_KP7,
-       [    8 ] = KEY_KP8,
-       [    9 ] = KEY_KP9,
-
-       [ 0x0a ] = KEY_AGAIN,          /* Recall */
-       [ 0x0b ] = KEY_CHANNELUP,
-       [ 0x0c ] = KEY_VOLUMEUP,
-       [ 0x0d ] = KEY_MODE,           /* Stereo */
-       [ 0x0e ] = KEY_STOP,
-       [ 0x0f ] = KEY_PREVIOUSSONG,
-       [ 0x10 ] = KEY_ZOOM,
-       [ 0x11 ] = KEY_TUNER,          /* Source */
-       [ 0x12 ] = KEY_POWER,
-       [ 0x13 ] = KEY_MUTE,
-       [ 0x15 ] = KEY_CHANNELDOWN,
-       [ 0x18 ] = KEY_VOLUMEDOWN,
-       [ 0x19 ] = KEY_SHUFFLE,        /* Snapshot */
-       [ 0x1a ] = KEY_NEXTSONG,
-       [ 0x1b ] = KEY_TEXT,           /* Time Shift */
-       [ 0x1c ] = KEY_RADIO,          /* FM Radio */
-       [ 0x1d ] = KEY_RECORD,
-       [ 0x1e ] = KEY_PAUSE,
-};
-
-
 /* -------------------- GPIO generic keycode builder -------------------- */
 
 static int build_key(struct saa7134_dev *dev)
@@ -628,27 +149,27 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_FLYVIDEO3000:
        case SAA7134_BOARD_FLYTVPLATINUM_FM:
        case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
-               ir_codes     = flyvideo_codes;
+               ir_codes     = ir_codes_flyvideo;
                mask_keycode = 0xEC00000;
                mask_keydown = 0x0040000;
                break;
        case SAA7134_BOARD_CINERGY400:
        case SAA7134_BOARD_CINERGY600:
        case SAA7134_BOARD_CINERGY600_MK3:
-               ir_codes     = cinergy_codes;
+               ir_codes     = ir_codes_cinergy;
                mask_keycode = 0x00003f;
                mask_keyup   = 0x040000;
                break;
        case SAA7134_BOARD_ECS_TVP3XP:
        case SAA7134_BOARD_ECS_TVP3XP_4CB5:
-               ir_codes     = eztv_codes;
+               ir_codes     = ir_codes_eztv;
                mask_keycode = 0x00017c;
                mask_keyup   = 0x000002;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_KWORLD_XPERT:
        case SAA7134_BOARD_AVACSSMARTTV:
-               ir_codes     = avacssmart_codes;
+               ir_codes     = ir_codes_pixelview;
                mask_keycode = 0x00001F;
                mask_keyup   = 0x000020;
                polling      = 50; // ms
@@ -660,7 +181,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
-               ir_codes     = md2819_codes;
+               ir_codes     = ir_codes_avermedia;
                mask_keycode = 0x0007C8;
                mask_keydown = 0x000010;
                polling      = 50; // ms
@@ -669,7 +190,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
                break;
        case SAA7134_BOARD_KWORLD_TERMINATOR:
-               ir_codes     = avacssmart_codes;
+               ir_codes     = ir_codes_pixelview;
                mask_keycode = 0x00001f;
                mask_keyup   = 0x000060;
                polling      = 50; // ms
@@ -677,19 +198,19 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_MANLI_MTV001:
        case SAA7134_BOARD_MANLI_MTV002:
        case SAA7134_BOARD_BEHOLD_409FM:
-               ir_codes     = manli_codes;
+               ir_codes     = ir_codes_manli;
                mask_keycode = 0x001f00;
                mask_keyup   = 0x004000;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
-               ir_codes     = pctv_sedna_codes;
+               ir_codes     = ir_codes_pctv_sedna;
                mask_keycode = 0x001f00;
                mask_keyup   = 0x004000;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_GOTVIEW_7135:
-               ir_codes     = gotview7135_codes;
+               ir_codes     = ir_codes_gotview7135;
                mask_keycode = 0x0003EC;
                mask_keyup   = 0x008000;
                mask_keydown = 0x000010;
@@ -698,17 +219,23 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
        case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
        case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
-               ir_codes     = videomate_tv_pvr_codes;
+               ir_codes     = ir_codes_videomate_tv_pvr;
                mask_keycode = 0x00003F;
                mask_keyup   = 0x400000;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
-               ir_codes     = videomate_tv_pvr_codes;
+               ir_codes     = ir_codes_videomate_tv_pvr;
                mask_keycode = 0x003F00;
                mask_keyup   = 0x040000;
                break;
+       case SAA7134_BOARD_FLYDVBT_LR301:
+       case SAA7134_BOARD_FLYDVBTDUO:
+               ir_codes     = ir_codes_flydvb;
+               mask_keycode = 0x0001F00;
+               mask_keydown = 0x0040000;
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
index 7448e38..d79d05f 100644 (file)
@@ -84,8 +84,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
 {
        int err;
 
-       if (!dev->dmasound.bufsize)
-               BUG();
+       BUG_ON(!dev->dmasound.bufsize);
        videobuf_dma_init(&dev->dmasound.dma);
        err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
                                       (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
@@ -96,8 +95,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
 
 static int dsp_buffer_free(struct saa7134_dev *dev)
 {
-       if (!dev->dmasound.blksize)
-               BUG();
+       BUG_ON(!dev->dmasound.blksize);
        videobuf_dma_free(&dev->dmasound.dma);
        dev->dmasound.blocks  = 0;
        dev->dmasound.blksize = 0;
@@ -254,7 +252,7 @@ static int dsp_open(struct inode *inode, struct file *file)
        if (NULL == dev)
                return -ENODEV;
 
-       down(&dev->dmasound.lock);
+       mutex_lock(&dev->dmasound.lock);
        err = -EBUSY;
        if (dev->dmasound.users_dsp)
                goto fail1;
@@ -270,13 +268,13 @@ static int dsp_open(struct inode *inode, struct file *file)
        if (0 != err)
                goto fail2;
 
-       up(&dev->dmasound.lock);
+       mutex_unlock(&dev->dmasound.lock);
        return 0;
 
  fail2:
        dev->dmasound.users_dsp--;
  fail1:
-       up(&dev->dmasound.lock);
+       mutex_unlock(&dev->dmasound.lock);
        return err;
 }
 
@@ -284,13 +282,13 @@ static int dsp_release(struct inode *inode, struct file *file)
 {
        struct saa7134_dev *dev = file->private_data;
 
-       down(&dev->dmasound.lock);
+       mutex_lock(&dev->dmasound.lock);
        if (dev->dmasound.recording_on)
                dsp_rec_stop(dev);
        dsp_buffer_free(dev);
        dev->dmasound.users_dsp--;
        file->private_data = NULL;
-       up(&dev->dmasound.lock);
+       mutex_unlock(&dev->dmasound.lock);
        return 0;
 }
 
@@ -304,7 +302,7 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
        int err,ret = 0;
 
        add_wait_queue(&dev->dmasound.wq, &wait);
-       down(&dev->dmasound.lock);
+       mutex_lock(&dev->dmasound.lock);
        while (count > 0) {
                /* wait for data if needed */
                if (0 == dev->dmasound.read_count) {
@@ -328,12 +326,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
                                        ret = -EAGAIN;
                                break;
                        }
-                       up(&dev->dmasound.lock);
+                       mutex_unlock(&dev->dmasound.lock);
                        set_current_state(TASK_INTERRUPTIBLE);
                        if (0 == dev->dmasound.read_count)
                                schedule();
                        set_current_state(TASK_RUNNING);
-                       down(&dev->dmasound.lock);
+                       mutex_lock(&dev->dmasound.lock);
                        if (signal_pending(current)) {
                                if (0 == ret)
                                        ret = -EINTR;
@@ -362,7 +360,7 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
                if (dev->dmasound.read_offset == dev->dmasound.bufsize)
                        dev->dmasound.read_offset = 0;
        }
-       up(&dev->dmasound.lock);
+       mutex_unlock(&dev->dmasound.lock);
        remove_wait_queue(&dev->dmasound.wq, &wait);
        return ret;
 }
@@ -435,13 +433,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
        case SNDCTL_DSP_STEREO:
                if (get_user(val, p))
                        return -EFAULT;
-               down(&dev->dmasound.lock);
+               mutex_lock(&dev->dmasound.lock);
                dev->dmasound.channels = val ? 2 : 1;
                if (dev->dmasound.recording_on) {
                        dsp_rec_stop(dev);
                        dsp_rec_start(dev);
                }
-               up(&dev->dmasound.lock);
+               mutex_unlock(&dev->dmasound.lock);
                return put_user(dev->dmasound.channels-1, p);
 
        case SNDCTL_DSP_CHANNELS:
@@ -449,13 +447,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
                        return -EFAULT;
                if (val != 1 && val != 2)
                        return -EINVAL;
-               down(&dev->dmasound.lock);
+               mutex_lock(&dev->dmasound.lock);
                dev->dmasound.channels = val;
                if (dev->dmasound.recording_on) {
                        dsp_rec_stop(dev);
                        dsp_rec_start(dev);
                }
-               up(&dev->dmasound.lock);
+               mutex_unlock(&dev->dmasound.lock);
                /* fall through */
        case SOUND_PCM_READ_CHANNELS:
                return put_user(dev->dmasound.channels, p);
@@ -478,13 +476,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
                case AFMT_U16_BE:
                case AFMT_S16_LE:
                case AFMT_S16_BE:
-                       down(&dev->dmasound.lock);
+                       mutex_lock(&dev->dmasound.lock);
                        dev->dmasound.afmt = val;
                        if (dev->dmasound.recording_on) {
                                dsp_rec_stop(dev);
                                dsp_rec_start(dev);
                        }
-                       up(&dev->dmasound.lock);
+                       mutex_unlock(&dev->dmasound.lock);
                        return put_user(dev->dmasound.afmt, p);
                default:
                        return -EINVAL;
@@ -509,10 +507,10 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
                return 0;
 
        case SNDCTL_DSP_RESET:
-               down(&dev->dmasound.lock);
+               mutex_lock(&dev->dmasound.lock);
                if (dev->dmasound.recording_on)
                        dsp_rec_stop(dev);
-               up(&dev->dmasound.lock);
+               mutex_unlock(&dev->dmasound.lock);
                return 0;
        case SNDCTL_DSP_GETBLKSIZE:
                return put_user(dev->dmasound.blksize, p);
@@ -556,10 +554,10 @@ static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
        poll_wait(file, &dev->dmasound.wq, wait);
 
        if (0 == dev->dmasound.read_count) {
-               down(&dev->dmasound.lock);
+               mutex_lock(&dev->dmasound.lock);
                if (!dev->dmasound.recording_on)
                        dsp_rec_start(dev);
-               up(&dev->dmasound.lock);
+               mutex_unlock(&dev->dmasound.lock);
        } else
                mask |= (POLLIN | POLLRDNORM);
        return mask;
@@ -852,7 +850,7 @@ int saa7134_oss_init1(struct saa7134_dev *dev)
                return -1;
 
        /* general */
-       init_MUTEX(&dev->dmasound.lock);
+       mutex_init(&dev->dmasound.lock);
        init_waitqueue_head(&dev->dmasound.wq);
 
        switch (dev->pci->device) {
index afa4dcb..3043233 100644 (file)
@@ -140,6 +140,12 @@ static struct saa7134_tvaudio tvaudio[] = {
                .carr2         = 5850,
                .mode          = TVAUDIO_NICAM_AM,
        },{
+               .name          = "SECAM-L MONO",
+               .std           = V4L2_STD_SECAM,
+               .carr1         = 6500,
+               .carr2         = -1,
+               .mode          = TVAUDIO_AM_MONO,
+       },{
                .name          = "SECAM-D/K",
                .std           = V4L2_STD_SECAM,
                .carr1         = 6500,
@@ -334,6 +340,12 @@ static void tvaudio_setmode(struct saa7134_dev *dev,
                saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa1);
                saa_writeb(SAA7134_NICAM_CONFIG,              0x00);
                break;
+       case TVAUDIO_AM_MONO:
+               saa_writeb(SAA7134_DEMODULATOR,               0x12);
+               saa_writeb(SAA7134_DCXO_IDENT_CTRL,           0x00);
+               saa_writeb(SAA7134_FM_DEEMPHASIS,             0x44);
+               saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT,  0xa0);
+               break;
        case TVAUDIO_FM_SAT_STEREO:
                /* not implemented (yet) */
                break;
@@ -414,6 +426,7 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
 
        switch (audio->mode) {
        case TVAUDIO_FM_MONO:
+       case TVAUDIO_AM_MONO:
                return V4L2_TUNER_SUB_MONO;
        case TVAUDIO_FM_K_STEREO:
        case TVAUDIO_FM_BG_STEREO:
@@ -480,6 +493,7 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
 
        switch (audio->mode) {
        case TVAUDIO_FM_MONO:
+       case TVAUDIO_AM_MONO:
                /* nothing to do ... */
                break;
        case TVAUDIO_FM_K_STEREO:
index e97426b..57a11e7 100644 (file)
@@ -460,17 +460,17 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int
                return 1;
 
        /* is it free? */
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        if (dev->resources & bit) {
                /* no, someone else uses it */
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
        fh->resources  |= bit;
        dev->resources |= bit;
        dprintk("res: get %d\n",bit);
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
        return 1;
 }
 
@@ -489,14 +489,13 @@ int res_locked(struct saa7134_dev *dev, unsigned int bit)
 static
 void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
 {
-       if ((fh->resources & bits) != bits)
-               BUG();
+       BUG_ON((fh->resources & bits) != bits);
 
-       down(&dev->lock);
+       mutex_lock(&dev->lock);
        fh->resources  &= ~bits;
        dev->resources &= ~bits;
        dprintk("res: put %d\n",bits);
-       up(&dev->lock);
+       mutex_unlock(&dev->lock);
 }
 
 /* ------------------------------------------------------------------ */
@@ -1340,21 +1339,21 @@ video_poll(struct file *file, struct poll_table_struct *wait)
                if (!list_empty(&fh->cap.stream))
                        buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
        } else {
-               down(&fh->cap.lock);
+               mutex_lock(&fh->cap.lock);
                if (UNSET == fh->cap.read_off) {
                        /* need to capture a new frame */
                        if (res_locked(fh->dev,RESOURCE_VIDEO)) {
-                               up(&fh->cap.lock);
+                               mutex_unlock(&fh->cap.lock);
                                return POLLERR;
                        }
                        if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
-                               up(&fh->cap.lock);
+                               mutex_unlock(&fh->cap.lock);
                                return POLLERR;
                        }
                        fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
                        fh->cap.read_off = 0;
                }
-               up(&fh->cap.lock);
+               mutex_unlock(&fh->cap.lock);
                buf = fh->cap.read_buf;
        }
 
@@ -1463,6 +1462,10 @@ static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
                        f->fmt.pix.height * f->fmt.pix.bytesperline;
                return 0;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (saa7134_no_overlay > 0) {
+                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                       return -EINVAL;
+               }
                f->fmt.win = fh->win;
                return 0;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
@@ -1527,6 +1530,10 @@ static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
                return 0;
        }
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (saa7134_no_overlay > 0) {
+                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                       return -EINVAL;
+               }
                err = verify_preview(dev,&f->fmt.win);
                if (0 != err)
                        return err;
@@ -1557,18 +1564,22 @@ static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
                fh->cap.field = f->fmt.pix.field;
                return 0;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (saa7134_no_overlay > 0) {
+                       printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                       return -EINVAL;
+               }
                err = verify_preview(dev,&f->fmt.win);
                if (0 != err)
                        return err;
 
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
                fh->win    = f->fmt.win;
                fh->nclips = f->fmt.win.clipcount;
                if (fh->nclips > 8)
                        fh->nclips = 8;
                if (copy_from_user(fh->clips,f->fmt.win.clips,
                                   sizeof(struct v4l2_clip)*fh->nclips)) {
-                       up(&dev->lock);
+                       mutex_unlock(&dev->lock);
                        return -EFAULT;
                }
 
@@ -1578,7 +1589,7 @@ static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
                        start_preview(dev,fh);
                        spin_unlock_irqrestore(&dev->slock,flags);
                }
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
                saa7134_vbi_fmt(dev,f);
@@ -1612,9 +1623,9 @@ int saa7134_common_ioctl(struct saa7134_dev *dev,
                return get_control(dev,arg);
        case VIDIOC_S_CTRL:
        {
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
                err = set_control(dev,NULL,arg);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return err;
        }
        /* --- input switching --------------------------------------- */
@@ -1664,9 +1675,9 @@ int saa7134_common_ioctl(struct saa7134_dev *dev,
                        return -EINVAL;
                if (NULL == card_in(dev,*i).name)
                        return -EINVAL;
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
                video_mux(dev,*i);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
 
@@ -1716,11 +1727,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                cap->version = SAA7134_VERSION_CODE;
                cap->capabilities =
                        V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_VIDEO_OVERLAY |
                        V4L2_CAP_VBI_CAPTURE |
                        V4L2_CAP_READWRITE |
                        V4L2_CAP_STREAMING |
                        V4L2_CAP_TUNER;
+               if (saa7134_no_overlay <= 0) {
+                       cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+               }
 
                if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
                        cap->capabilities &= ~V4L2_CAP_TUNER;
@@ -1766,7 +1779,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                if (i == TVNORMS)
                        return -EINVAL;
 
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
                if (res_check(fh, RESOURCE_OVERLAY)) {
                        spin_lock_irqsave(&dev->slock,flags);
                        stop_preview(dev,fh);
@@ -1776,7 +1789,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                } else
                        set_tvnorm(dev,&tvnorms[i]);
                saa7134_tvaudio_do_scan(dev);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
 
@@ -1909,13 +1922,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
                        return -EINVAL;
-               down(&dev->lock);
+               mutex_lock(&dev->lock);
                dev->ctl_freq = f->frequency;
 
                saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
 
                saa7134_tvaudio_do_scan(dev);
-               up(&dev->lock);
+               mutex_unlock(&dev->lock);
                return 0;
        }
 
@@ -1971,6 +1984,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                switch (type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       if (saa7134_no_overlay > 0) {
+                               printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+                               return -EINVAL;
+                       }
                        if (index >= FORMATS)
                                return -EINVAL;
                        if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
@@ -2031,6 +2048,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                int *on = arg;
 
                if (*on) {
+                       if (saa7134_no_overlay > 0) {
+                               printk ("no_overlay\n");
+                               return -EINVAL;
+                       }
+
                        if (!res_get(dev,fh,RESOURCE_OVERLAY))
                                return -EBUSY;
                        spin_lock_irqsave(&dev->slock,flags);
@@ -2282,7 +2304,7 @@ static struct file_operations radio_fops =
 struct video_device saa7134_video_template =
 {
        .name          = "saa7134-video",
-       .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
+       .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
                         VID_TYPE_CLIPPING|VID_TYPE_SCALES,
        .hardware      = 0,
        .fops          = &video_fops,
index 3261d8b..17ba34f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/input.h>
 #include <linux/notifier.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 
@@ -60,6 +61,7 @@ enum saa7134_tvaudio_mode {
        TVAUDIO_FM_K_STEREO   = 4,
        TVAUDIO_NICAM_AM      = 5,
        TVAUDIO_NICAM_FM      = 6,
+       TVAUDIO_AM_MONO       = 7
 };
 
 enum saa7134_audio_in {
@@ -210,6 +212,15 @@ struct saa7134_format {
 #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS  82
 #define SAA7134_BOARD_CINERGY250PCI 83
 #define SAA7134_BOARD_FLYDVB_TRIO 84
+#define SAA7134_BOARD_AVERMEDIA_777 85
+#define SAA7134_BOARD_FLYDVBT_LR301 86
+#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87
+#define SAA7134_BOARD_TEVION_DVBT_220RF 88
+#define SAA7134_BOARD_ELSA_700TV       89
+#define SAA7134_BOARD_KWORLD_ATSC110   90
+#define SAA7134_BOARD_AVERMEDIA_A169_B 91
+#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
+#define SAA7134_BOARD_MD7134_BRIDGE_2     93
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -359,7 +370,7 @@ struct saa7134_fh {
 
 /* dmasound dsp status */
 struct saa7134_dmasound {
-       struct semaphore           lock;
+       struct mutex               lock;
        int                        minor_mixer;
        int                        minor_dsp;
        unsigned int               users_dsp;
@@ -423,7 +434,7 @@ struct saa7134_mpeg_ops {
 /* global device status */
 struct saa7134_dev {
        struct list_head           devlist;
-       struct semaphore           lock;
+       struct mutex               lock;
        spinlock_t                 slock;
 #ifdef VIDIOC_G_PRIORITY
        struct v4l2_prio_state     prio;
@@ -546,6 +557,7 @@ struct saa7134_dev {
 /* saa7134-core.c                                              */
 
 extern struct list_head  saa7134_devlist;
+extern int saa7134_no_overlay;
 
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
 
index a796a4e..027c8a0 100644 (file)
@@ -281,7 +281,7 @@ static void tda827xa_agcf(struct i2c_client *c)
 static void tda8290_i2c_bridge(struct i2c_client *c, int close)
 {
        unsigned char  enable[2] = { 0x21, 0xC0 };
-       unsigned char disable[2] = { 0x21, 0x80 };
+       unsigned char disable[2] = { 0x21, 0x00 };
        unsigned char *msg;
        if(close) {
                msg = enable;
@@ -302,6 +302,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
        unsigned char soft_reset[]  = { 0x00, 0x00 };
        unsigned char easy_mode[]   = { 0x01, t->tda8290_easy_mode };
        unsigned char expert_mode[] = { 0x01, 0x80 };
+       unsigned char agc_out_on[]  = { 0x02, 0x00 };
        unsigned char gainset_off[] = { 0x28, 0x14 };
        unsigned char if_agc_spd[]  = { 0x0f, 0x88 };
        unsigned char adc_head_6[]  = { 0x05, 0x04 };
@@ -320,6 +321,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
                      pll_stat;
 
        i2c_master_send(c, easy_mode, 2);
+       i2c_master_send(c, agc_out_on, 2);
        i2c_master_send(c, soft_reset, 2);
        msleep(1);
 
@@ -470,6 +472,7 @@ static void standby(struct i2c_client *c)
        struct tuner *t = i2c_get_clientdata(c);
        unsigned char cb1[] = { 0x30, 0xD0 };
        unsigned char tda8290_standby[] = { 0x00, 0x02 };
+       unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
        struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
 
        tda8290_i2c_bridge(c, 1);
@@ -477,6 +480,7 @@ static void standby(struct i2c_client *c)
                cb1[1] = 0x90;
        i2c_transfer(c->adapter, &msg, 1);
        tda8290_i2c_bridge(c, 0);
+       i2c_master_send(c, tda8290_agc_tri, 2);
        i2c_master_send(c, tda8290_standby, 2);
 }
 
@@ -565,7 +569,7 @@ int tda8290_init(struct i2c_client *c)
                strlcpy(c->name, "tda8290+75a", sizeof(c->name));
                t->tda827x_ver = 2;
        }
-       tuner_info("tuner: type set to %s\n", c->name);
+       tuner_info("type set to %s\n", c->name);
 
        t->set_tv_freq    = set_tv_freq;
        t->set_radio_freq = set_radio_freq;
index ed4c041..0243700 100644 (file)
@@ -24,6 +24,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
 
+
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
@@ -222,7 +223,7 @@ static int detach(struct i2c_client *client)
 
 static struct i2c_driver driver = {
        .driver = {
-               .name   = "tda9840",
+               .name = "tda9840",
        },
        .id     = I2C_DRIVERID_TDA9840,
        .attach_adapter = attach,
index bb35844..774ed0d 100644 (file)
@@ -26,6 +26,7 @@
     Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA.
   */
 
+
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
@@ -107,7 +108,7 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
 {
        u8 byte = 0;
        int ret;
-       
+
        dprintk("adr:0x%02x, i:%d, o:%d\n", client->addr, i, o);
 
        /* check if the pins are valid */
@@ -191,7 +192,7 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static struct i2c_driver driver = {
        .driver = {
-               .name   = "tea6415c",
+               .name = "tea6415c",
        },
        .id     = I2C_DRIVERID_TEA6415C,
        .attach_adapter = attach,
index 4dcba5a..ad7d287 100644 (file)
@@ -26,6 +26,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
 
+
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
@@ -83,7 +84,7 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
                dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret);
                return -EIO;
        }
-       
+
        return 0;
 }
 
@@ -167,7 +168,7 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static struct i2c_driver driver = {
        .driver = {
-               .name   = "tea6420",
+               .name = "tea6420",
        },
        .id     = I2C_DRIVERID_TEA6420,
        .attach_adapter = attach,
index b6101bf..32e1849 100644 (file)
@@ -173,7 +173,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
        }
 
        t->type = type;
-
        switch (t->type) {
        case TUNER_MT2032:
                microtune_init(c);
@@ -404,15 +403,16 @@ static void tuner_status(struct i2c_client *client)
        tuner_info("Tuner mode:      %s\n", p);
        tuner_info("Frequency:       %lu.%02lu MHz\n", freq, freq_fraction);
        tuner_info("Standard:        0x%08llx\n", t->std);
-       if (t->mode == V4L2_TUNER_RADIO) {
-               if (t->has_signal) {
-                       tuner_info("Signal strength: %d\n", t->has_signal(client));
-               }
-               if (t->is_stereo) {
-                       tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
-               }
+       if (t->mode != V4L2_TUNER_RADIO)
+              return;
+       if (t->has_signal) {
+               tuner_info("Signal strength: %d\n", t->has_signal(client));
+       }
+       if (t->is_stereo) {
+               tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
        }
 }
+
 /* ---------------------------------------------------------------------- */
 
 /* static var Used only in tuner_attach and tuner_probe */
@@ -744,33 +744,29 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                                return 0;
                        switch_v4l2();
 
-                       if (V4L2_TUNER_RADIO == t->mode) {
-
-                               if (t->has_signal)
-                                       tuner->signal = t->has_signal(client);
-
-                               if (t->is_stereo) {
-                                       if (t->is_stereo(client)) {
-                                               tuner->rxsubchans =
-                                                   V4L2_TUNER_SUB_STEREO |
-                                                   V4L2_TUNER_SUB_MONO;
-                                       } else {
-                                               tuner->rxsubchans =
-                                                   V4L2_TUNER_SUB_MONO;
-                                       }
-                               }
-
-                               tuner->capability |=
-                                   V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-
-                               tuner->audmode = t->audmode;
-
-                               tuner->rangelow = radio_range[0] * 16000;
-                               tuner->rangehigh = radio_range[1] * 16000;
-                       } else {
+                       tuner->type = t->mode;
+                       if (t->mode != V4L2_TUNER_RADIO) {
                                tuner->rangelow = tv_range[0] * 16;
                                tuner->rangehigh = tv_range[1] * 16;
+                               break;
                        }
+
+                       /* radio mode */
+                       if (t->has_signal)
+                               tuner->signal = t->has_signal(client);
+
+                       tuner->rxsubchans =
+                               V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+                       if (t->is_stereo) {
+                               tuner->rxsubchans = t->is_stereo(client) ?
+                                       V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+                       }
+
+                       tuner->capability |=
+                           V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+                       tuner->audmode = t->audmode;
+                       tuner->rangelow = radio_range[0] * 16000;
+                       tuner->rangehigh = radio_range[1] * 16000;
                        break;
                }
        case VIDIOC_S_TUNER:
@@ -782,10 +778,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
                        switch_v4l2();
 
-                       if (V4L2_TUNER_RADIO == t->mode) {
-                               t->audmode = tuner->audmode;
-                               set_radio_freq(client, t->radio_freq);
-                       }
+                       /* do nothing unless we're a radio tuner */
+                       if (t->mode != V4L2_TUNER_RADIO)
+                               break;
+                       t->audmode = tuner->audmode;
+                       set_radio_freq(client, t->radio_freq);
                        break;
                }
        case VIDIOC_LOG_STATUS:
index 37977ff..5d7abed 100644 (file)
@@ -79,17 +79,6 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
 #define TUNER_PLL_LOCKED   0x40
 #define TUNER_STEREO_MK3   0x04
 
-#define TUNER_PARAM_ANALOG 0  /* to be removed */
-/* FIXME:
- * Right now, all tuners are using the first tuner_params[] array element
- * for analog mode. In the future, we will be merging similar tuner
- * definitions together, such that each tuner definition will have a
- * tuner_params struct for each available video standard. At that point,
- * TUNER_PARAM_ANALOG will be removed, and the tuner_params[] array
- * element will be chosen based on the video standard in use.
- *
- */
-
 /* ---------------------------------------------------------------------- */
 
 static int tuner_getstatus(struct i2c_client *c)
@@ -133,14 +122,53 @@ static int tuner_stereo(struct i2c_client *c)
 static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       u8 config, tuneraddr;
+       u8 config, cb, tuneraddr;
        u16 div;
        struct tunertype *tun;
        u8 buffer[4];
        int rc, IFPCoff, i, j;
+       enum param_type desired_type;
 
        tun = &tuners[t->type];
-       j = TUNER_PARAM_ANALOG;
+
+       /* IFPCoff = Video Intermediate Frequency - Vif:
+               940  =16*58.75  NTSC/J (Japan)
+               732  =16*45.75  M/N STD
+               704  =16*44     ATSC (at DVB code)
+               632  =16*39.50  I U.K.
+               622.4=16*38.90  B/G D/K I, L STD
+               592  =16*37.00  D China
+               590  =16.36.875 B Australia
+               543.2=16*33.95  L' STD
+               171.2=16*10.70  FM Radio (at set_radio_freq)
+       */
+
+       if (t->std == V4L2_STD_NTSC_M_JP) {
+               IFPCoff      = 940;
+               desired_type = TUNER_PARAM_TYPE_NTSC;
+       } else if ((t->std & V4L2_STD_MN) &&
+                 !(t->std & ~V4L2_STD_MN)) {
+               IFPCoff      = 732;
+               desired_type = TUNER_PARAM_TYPE_NTSC;
+       } else if (t->std == V4L2_STD_SECAM_LC) {
+               IFPCoff      = 543;
+               desired_type = TUNER_PARAM_TYPE_SECAM;
+       } else {
+               IFPCoff      = 623;
+               desired_type = TUNER_PARAM_TYPE_PAL;
+       }
+
+       for (j = 0; j < tun->count-1; j++) {
+               if (desired_type != tun->params[j].type)
+                       continue;
+               break;
+       }
+       /* use default tuner_params if desired_type not available */
+       if (desired_type != tun->params[j].type) {
+               tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n",
+                         IFPCoff,t->type);
+               j = 0;
+       }
 
        for (i = 0; i < tun->params[j].count; i++) {
                if (freq > tun->params[j].ranges[i].limit)
@@ -152,11 +180,20 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                                freq, tun->params[j].ranges[i - 1].limit);
                freq = tun->params[j].ranges[--i].limit;
        }
-       config = tun->params[j].ranges[i].cb;
-       /*  i == 0 -> VHF_LO  */
-       /*  i == 1 -> VHF_HI  */
-       /*  i == 2 -> UHF     */
-       tuner_dbg("tv: range %d\n",i);
+       config = tun->params[j].ranges[i].config;
+       cb     = tun->params[j].ranges[i].cb;
+       /*  i == 0 -> VHF_LO
+        *  i == 1 -> VHF_HI
+        *  i == 2 -> UHF     */
+       tuner_dbg("tv: param %d, range %d\n",j,i);
+
+       div=freq + IFPCoff + offset;
+
+       tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
+                                       freq / 16, freq % 16 * 100 / 16,
+                                       IFPCoff / 16, IFPCoff % 16 * 100 / 16,
+                                       offset / 16, offset % 16 * 100 / 16,
+                                       div);
 
        /* tv norm specific stuff for multi-norm tuners */
        switch (t->type) {
@@ -164,40 +201,40 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                /* 0x01 -> ??? no change ??? */
                /* 0x02 -> PAL BDGHI / SECAM L */
                /* 0x04 -> ??? PAL others / SECAM others ??? */
-               config &= ~0x02;
+               cb &= ~0x02;
                if (t->std & V4L2_STD_SECAM)
-                       config |= 0x02;
+                       cb |= 0x02;
                break;
 
        case TUNER_TEMIC_4046FM5:
-               config &= ~0x0f;
+               cb &= ~0x0f;
 
                if (t->std & V4L2_STD_PAL_BG) {
-                       config |= TEMIC_SET_PAL_BG;
+                       cb |= TEMIC_SET_PAL_BG;
 
                } else if (t->std & V4L2_STD_PAL_I) {
-                       config |= TEMIC_SET_PAL_I;
+                       cb |= TEMIC_SET_PAL_I;
 
                } else if (t->std & V4L2_STD_PAL_DK) {
-                       config |= TEMIC_SET_PAL_DK;
+                       cb |= TEMIC_SET_PAL_DK;
 
                } else if (t->std & V4L2_STD_SECAM_L) {
-                       config |= TEMIC_SET_PAL_L;
+                       cb |= TEMIC_SET_PAL_L;
 
                }
                break;
 
        case TUNER_PHILIPS_FQ1216ME:
-               config &= ~0x0f;
+               cb &= ~0x0f;
 
                if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
-                       config |= PHILIPS_SET_PAL_BGDK;
+                       cb |= PHILIPS_SET_PAL_BGDK;
 
                } else if (t->std & V4L2_STD_PAL_I) {
-                       config |= PHILIPS_SET_PAL_I;
+                       cb |= PHILIPS_SET_PAL_I;
 
                } else if (t->std & V4L2_STD_SECAM_L) {
-                       config |= PHILIPS_SET_PAL_L;
+                       cb |= PHILIPS_SET_PAL_L;
 
                }
                break;
@@ -207,15 +244,15 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                /* 0x01 -> ATSC antenna input 2 */
                /* 0x02 -> NTSC antenna input 1 */
                /* 0x03 -> NTSC antenna input 2 */
-               config &= ~0x03;
+               cb &= ~0x03;
                if (!(t->std & V4L2_STD_ATSC))
-                       config |= 2;
+                       cb |= 2;
                /* FIXME: input */
                break;
 
        case TUNER_MICROTUNE_4042FI5:
                /* Set the charge pump for fast tuning */
-               tun->params[j].config |= TUNER_CHARGE_PUMP;
+               config |= TUNER_CHARGE_PUMP;
                break;
 
        case TUNER_PHILIPS_TUV1236D:
@@ -227,9 +264,9 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                buffer[1] = 0x00;
                buffer[2] = 0x17;
                buffer[3] = 0x00;
-               config &= ~0x40;
+               cb &= ~0x40;
                if (t->std & V4L2_STD_ATSC) {
-                       config |= 0x40;
+                       cb |= 0x40;
                        buffer[1] = 0x04;
                }
                /* set to the correct mode (analog or digital) */
@@ -244,47 +281,16 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                break;
        }
 
-       /* IFPCoff = Video Intermediate Frequency - Vif:
-               940  =16*58.75  NTSC/J (Japan)
-               732  =16*45.75  M/N STD
-               704  =16*44     ATSC (at DVB code)
-               632  =16*39.50  I U.K.
-               622.4=16*38.90  B/G D/K I, L STD
-               592  =16*37.00  D China
-               590  =16.36.875 B Australia
-               543.2=16*33.95  L' STD
-               171.2=16*10.70  FM Radio (at set_radio_freq)
-       */
-
-       if (t->std == V4L2_STD_NTSC_M_JP) {
-               IFPCoff = 940;
-       } else if ((t->std & V4L2_STD_MN) &&
-                 !(t->std & ~V4L2_STD_MN)) {
-               IFPCoff = 732;
-       } else if (t->std == V4L2_STD_SECAM_LC) {
-               IFPCoff = 543;
-       } else {
-               IFPCoff = 623;
-       }
-
-       div=freq + IFPCoff + offset;
-
-       tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
-                                       freq / 16, freq % 16 * 100 / 16,
-                                       IFPCoff / 16, IFPCoff % 16 * 100 / 16,
-                                       offset / 16, offset % 16 * 100 / 16,
-                                       div);
-
        if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
-               buffer[0] = tun->params[j].config;
-               buffer[1] = config;
+               buffer[0] = config;
+               buffer[1] = cb;
                buffer[2] = (div>>8) & 0x7f;
                buffer[3] = div      & 0xff;
        } else {
                buffer[0] = (div>>8) & 0x7f;
                buffer[1] = div      & 0xff;
-               buffer[2] = tun->params[j].config;
-               buffer[3] = config;
+               buffer[2] = config;
+               buffer[3] = cb;
        }
        t->last_div = div;
        tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
@@ -312,11 +318,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                }
 
                /* Set the charge pump for optimized phase noise figure */
-               tun->params[j].config &= ~TUNER_CHARGE_PUMP;
+               config &= ~TUNER_CHARGE_PUMP;
                buffer[0] = (div>>8) & 0x7f;
                buffer[1] = div      & 0xff;
-               buffer[2] = tun->params[j].config;
-               buffer[3] = config;
+               buffer[2] = config;
+               buffer[3] = cb;
                tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
                       buffer[0],buffer[1],buffer[2],buffer[3]);
 
@@ -332,12 +338,21 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
        u8 buffer[4];
        u16 div;
        int rc, j;
+       enum param_type desired_type = TUNER_PARAM_TYPE_RADIO;
 
        tun = &tuners[t->type];
-       j = TUNER_PARAM_ANALOG;
+
+       for (j = 0; j < tun->count-1; j++) {
+               if (desired_type != tun->params[j].type)
+                       continue;
+               break;
+       }
+       /* use default tuner_params if desired_type not available */
+       if (desired_type != tun->params[j].type)
+               j = 0;
 
        div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */
-       buffer[2] = (tun->params[j].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
+       buffer[2] = (tun->params[j].ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
 
        switch (t->type) {
        case TUNER_TENA_9533_DI:
@@ -349,6 +364,9 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
        case TUNER_PHILIPS_FMD1216ME_MK3:
                buffer[3] = 0x19;
                break;
+       case TUNER_TNF_5335MF:
+               buffer[3] = 0x11;
+               break;
        case TUNER_PHILIPS_FM1256_IH3:
                div = (20 * freq) / 16000 + (int)(33.3 * 20);  /* IF 33.3 MHz */
                buffer[3] = 0x19;
index 6fe7817..72e0f01 100644 (file)
  *     Each tuner_params array may contain one or more elements, one
  *     for each video standard.
  *
- *     FIXME: Some tuner_range definitions are duplicated, and
- *     should be eliminated.
+ *     FIXME: tuner_params struct contains an element, tda988x. We must
+ *     set this for all tuners that contain a tda988x chip, and then we
+ *     can remove this setting from the various card structs.
  *
- *     FIXME: tunertype struct contains an element, has_tda988x.
- *     We must set this for all tunertypes that contain a tda988x
- *     chip, and then we can remove this setting from the various
- *     card structs.
+ *     FIXME: Right now, all tuners are using the first tuner_params[]
+ *     array element for analog mode. In the future, we will be merging
+ *     similar tuner definitions together, such that each tuner definition
+ *     will have a tuner_params struct for each available video standard.
+ *     At that point, the tuner_params[] array element will be chosen
+ *     based on the video standard in use.
  */
 
 /* 0-9 */
 /* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */
 
 static struct tuner_range tuner_temic_pal_ranges[] = {
-       { 16 * 140.25 /*MHz*/, 0x02, },
-       { 16 * 463.25 /*MHz*/, 0x04, },
-       { 16 * 999.99        , 0x01, },
+       { 16 * 140.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
+       { 16 * 999.99        , 0x8e, 0x01, },
 };
 
 static struct tuner_params tuner_temic_pal_params[] = {
@@ -46,16 +49,15 @@ static struct tuner_params tuner_temic_pal_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_pal_ranges,
                .count  = ARRAY_SIZE(tuner_temic_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */
 
 static struct tuner_range tuner_philips_pal_i_ranges[] = {
-       { 16 * 140.25 /*MHz*/, 0xa0, },
-       { 16 * 463.25 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_pal_i_params[] = {
@@ -63,16 +65,15 @@ static struct tuner_params tuner_philips_pal_i_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_philips_pal_i_ranges,
                .count  = ARRAY_SIZE(tuner_philips_pal_i_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */
 
 static struct tuner_range tuner_philips_ntsc_ranges[] = {
-       { 16 * 157.25 /*MHz*/, 0xa0, },
-       { 16 * 451.25 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_ntsc_params[] = {
@@ -80,7 +81,6 @@ static struct tuner_params tuner_philips_ntsc_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_philips_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_philips_ntsc_ranges),
-               .config = 0x8e,
                .cb_first_if_lower_freq = 1,
        },
 };
@@ -88,9 +88,9 @@ static struct tuner_params tuner_philips_ntsc_params[] = {
 /* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */
 
 static struct tuner_range tuner_philips_secam_ranges[] = {
-       { 16 * 168.25 /*MHz*/, 0xa7, },
-       { 16 * 447.25 /*MHz*/, 0x97, },
-       { 16 * 999.99        , 0x37, },
+       { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, },
+       { 16 * 447.25 /*MHz*/, 0x8e, 0x97, },
+       { 16 * 999.99        , 0x8e, 0x37, },
 };
 
 static struct tuner_params tuner_philips_secam_params[] = {
@@ -98,7 +98,6 @@ static struct tuner_params tuner_philips_secam_params[] = {
                .type   = TUNER_PARAM_TYPE_SECAM,
                .ranges = tuner_philips_secam_ranges,
                .count  = ARRAY_SIZE(tuner_philips_secam_ranges),
-               .config = 0x8e,
                .cb_first_if_lower_freq = 1,
        },
 };
@@ -106,9 +105,9 @@ static struct tuner_params tuner_philips_secam_params[] = {
 /* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_pal_ranges[] = {
-       { 16 * 168.25 /*MHz*/, 0xa0, },
-       { 16 * 447.25 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 447.25 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_pal_params[] = {
@@ -116,7 +115,6 @@ static struct tuner_params tuner_philips_pal_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_philips_pal_ranges,
                .count  = ARRAY_SIZE(tuner_philips_pal_ranges),
-               .config = 0x8e,
                .cb_first_if_lower_freq = 1,
        },
 };
@@ -124,9 +122,9 @@ static struct tuner_params tuner_philips_pal_params[] = {
 /* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */
 
 static struct tuner_range tuner_temic_ntsc_ranges[] = {
-       { 16 * 157.25 /*MHz*/, 0x02, },
-       { 16 * 463.25 /*MHz*/, 0x04, },
-       { 16 * 999.99        , 0x01, },
+       { 16 * 157.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
+       { 16 * 999.99        , 0x8e, 0x01, },
 };
 
 static struct tuner_params tuner_temic_ntsc_params[] = {
@@ -134,16 +132,15 @@ static struct tuner_params tuner_temic_ntsc_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_temic_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_temic_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */
 
 static struct tuner_range tuner_temic_pal_i_ranges[] = {
-       { 16 * 170.00 /*MHz*/, 0x02, },
-       { 16 * 450.00 /*MHz*/, 0x04, },
-       { 16 * 999.99        , 0x01, },
+       { 16 * 170.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 450.00 /*MHz*/, 0x8e, 0x04, },
+       { 16 * 999.99        , 0x8e, 0x01, },
 };
 
 static struct tuner_params tuner_temic_pal_i_params[] = {
@@ -151,16 +148,15 @@ static struct tuner_params tuner_temic_pal_i_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_pal_i_ranges,
                .count  = ARRAY_SIZE(tuner_temic_pal_i_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */
 
 static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = {
-       { 16 * 157.25 /*MHz*/, 0xa0, },
-       { 16 * 463.25 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = {
@@ -168,16 +164,15 @@ static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_temic_4036fy5_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */
 
 static struct tuner_range tuner_alps_tsb_1_ranges[] = {
-       { 16 * 137.25 /*MHz*/, 0x01, },
-       { 16 * 385.25 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+       { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 385.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = {
@@ -185,7 +180,6 @@ static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_alps_tsb_1_ranges,
                .count  = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -197,16 +191,15 @@ static struct tuner_params tuner_alps_tsb_1_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_alps_tsb_1_ranges,
                .count  = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */
 
 static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = {
-       { 16 * 133.25 /*MHz*/, 0x01, },
-       { 16 * 351.25 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+       { 16 * 133.25 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 351.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_alps_tsbb5_params[] = {
@@ -214,7 +207,6 @@ static struct tuner_params tuner_alps_tsbb5_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_alps_tsb_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -225,7 +217,6 @@ static struct tuner_params tuner_alps_tsbe5_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_alps_tsb_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -236,33 +227,31 @@ static struct tuner_params tuner_alps_tsbc5_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_alps_tsb_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */
 
-static struct tuner_range tuner_temic_4006fh5_pal_ranges[] = {
-       { 16 * 170.00 /*MHz*/, 0xa0, },
-       { 16 * 450.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+static struct tuner_range tuner_lg_pal_ranges[] = {
+       { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 450.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4006fh5_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
-               .ranges = tuner_temic_4006fh5_pal_ranges,
-               .count  = ARRAY_SIZE(tuner_temic_4006fh5_pal_ranges),
-               .config = 0x8e,
+               .ranges = tuner_lg_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_lg_pal_ranges),
        },
 };
 
 /* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */
 
 static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = {
-       { 16 * 137.25 /*MHz*/, 0x14, },
-       { 16 * 385.25 /*MHz*/, 0x12, },
-       { 16 * 999.99        , 0x11, },
+       { 16 * 137.25 /*MHz*/, 0x8e, 0x14, },
+       { 16 * 385.25 /*MHz*/, 0x8e, 0x12, },
+       { 16 * 999.99        , 0x8e, 0x11, },
 };
 
 static struct tuner_params tuner_alps_tshc6_params[] = {
@@ -270,16 +259,15 @@ static struct tuner_params tuner_alps_tshc6_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_alps_tshc6_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */
 
 static struct tuner_range tuner_temic_pal_dk_ranges[] = {
-       { 16 * 168.25 /*MHz*/, 0xa0, },
-       { 16 * 456.25 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 456.25 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_pal_dk_params[] = {
@@ -287,16 +275,15 @@ static struct tuner_params tuner_temic_pal_dk_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_pal_dk_ranges,
                .count  = ARRAY_SIZE(tuner_temic_pal_dk_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */
 
 static struct tuner_range tuner_philips_ntsc_m_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0xa0, },
-       { 16 * 454.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_ntsc_m_params[] = {
@@ -304,16 +291,15 @@ static struct tuner_params tuner_philips_ntsc_m_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_philips_ntsc_m_ranges,
                .count  = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */
 
 static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = {
-       { 16 * 169.00 /*MHz*/, 0xa0, },
-       { 16 * 454.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = {
@@ -321,7 +307,6 @@ static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_40x6f_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -332,7 +317,6 @@ static struct tuner_params tuner_temic_4006fn5_multi_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_40x6f_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -340,9 +324,9 @@ static struct tuner_params tuner_temic_4006fn5_multi_params[] = {
 /* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */
 
 static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = {
-       { 16 * 141.00 /*MHz*/, 0xa0, },
-       { 16 * 464.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 464.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4009f_5_params[] = {
@@ -350,58 +334,42 @@ static struct tuner_params tuner_temic_4009f_5_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_4009f_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */
 
-static struct tuner_range tuner_temic_4039fr5_ntsc_ranges[] = {
-       { 16 * 158.00 /*MHz*/, 0xa0, },
-       { 16 * 453.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = {
+       { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_temic_4039fr5_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_temic_4039fr5_ntsc_ranges,
-               .count  = ARRAY_SIZE(tuner_temic_4039fr5_ntsc_ranges),
-               .config = 0x8e,
+               .ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
        },
 };
 
 /* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */
 
-static struct tuner_range tuner_temic_4046fm5_pal_ranges[] = {
-       { 16 * 169.00 /*MHz*/, 0xa0, },
-       { 16 * 454.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
-};
-
 static struct tuner_params tuner_temic_4046fm5_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
-               .ranges = tuner_temic_4046fm5_pal_ranges,
-               .count  = ARRAY_SIZE(tuner_temic_4046fm5_pal_ranges),
-               .config = 0x8e,
+               .ranges = tuner_temic_40x6f_5_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
        },
 };
 
 /* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */
 
-static struct tuner_range tuner_lg_pal_ranges[] = {
-       { 16 * 170.00 /*MHz*/, 0xa0, },
-       { 16 * 450.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
-};
-
 static struct tuner_params tuner_philips_pal_dk_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_lg_pal_ranges,
                .count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -412,7 +380,6 @@ static struct tuner_params tuner_philips_fq1216me_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_lg_pal_ranges,
                .count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -423,7 +390,6 @@ static struct tuner_params tuner_lg_pal_i_fm_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_lg_pal_ranges,
                .count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -434,16 +400,15 @@ static struct tuner_params tuner_lg_pal_i_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_lg_pal_ranges,
                .count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */
 
 static struct tuner_range tuner_lg_ntsc_fm_ranges[] = {
-       { 16 * 210.00 /*MHz*/, 0xa0, },
-       { 16 * 497.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 497.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_lg_ntsc_fm_params[] = {
@@ -451,7 +416,6 @@ static struct tuner_params tuner_lg_ntsc_fm_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_lg_ntsc_fm_ranges,
                .count  = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -462,7 +426,6 @@ static struct tuner_params tuner_lg_pal_fm_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_lg_pal_ranges,
                .count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -473,7 +436,6 @@ static struct tuner_params tuner_lg_pal_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_lg_pal_ranges,
                .count  = ARRAY_SIZE(tuner_lg_pal_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -485,16 +447,15 @@ static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_4009f_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */
 
 static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = {
-       { 16 * 137.25 /*MHz*/, 0x01, },
-       { 16 * 317.25 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+       { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 317.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_sharp_2u5jf5540_params[] = {
@@ -502,16 +463,15 @@ static struct tuner_params tuner_sharp_2u5jf5540_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_sharp_2u5jf5540_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */
 
 static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = {
-       { 16 * 169 /*MHz*/, 0xa0, },
-       { 16 * 464 /*MHz*/, 0x90, },
-       { 16 * 999.99     , 0x30, },
+       { 16 * 169 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 464 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99     , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = {
@@ -519,7 +479,6 @@ static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_samsung_pal_tcpm9091pd27_ranges,
                .count  = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -530,50 +489,35 @@ static struct tuner_params tuner_temic_4106fh5_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_4009f_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */
 
-static struct tuner_range tuner_temic_4012fy5_pal_ranges[] = {
-       { 16 * 140.25 /*MHz*/, 0x02, },
-       { 16 * 463.25 /*MHz*/, 0x04, },
-       { 16 * 999.99        , 0x01, },
-};
-
 static struct tuner_params tuner_temic_4012fy5_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
-               .ranges = tuner_temic_4012fy5_pal_ranges,
-               .count  = ARRAY_SIZE(tuner_temic_4012fy5_pal_ranges),
-               .config = 0x8e,
+               .ranges = tuner_temic_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_temic_pal_ranges),
        },
 };
 
 /* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */
 
-static struct tuner_range tuner_temic_4136_fy5_ntsc_ranges[] = {
-       { 16 * 158.00 /*MHz*/, 0xa0, },
-       { 16 * 453.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
-};
-
 static struct tuner_params tuner_temic_4136_fy5_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_temic_4136_fy5_ntsc_ranges,
-               .count  = ARRAY_SIZE(tuner_temic_4136_fy5_ntsc_ranges),
-               .config = 0x8e,
+               .ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
        },
 };
 
 /* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */
 
 static struct tuner_range tuner_lg_new_tapc_ranges[] = {
-       { 16 * 170.00 /*MHz*/, 0x01, },
-       { 16 * 450.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+       { 16 * 170.00 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 450.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_lg_pal_new_tapc_params[] = {
@@ -581,16 +525,15 @@ static struct tuner_params tuner_lg_pal_new_tapc_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_lg_new_tapc_ranges,
                .count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */
 
 static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = {
-       { 16 * 158.00 /*MHz*/, 0x01, },
-       { 16 * 442.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
+       { 16 * 158.00 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_fm1216me_mk3_params[] = {
@@ -598,7 +541,6 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_fm1216me_mk3_pal_ranges,
                .count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
-               .config = 0x8e,
                .cb_first_if_lower_freq = 1,
        },
 };
@@ -610,7 +552,6 @@ static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_lg_new_tapc_ranges,
                .count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -622,16 +563,15 @@ static struct tuner_params tuner_hitachi_ntsc_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_lg_new_tapc_ranges,
                .count  = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = {
-       { 16 * 140.25 /*MHz*/, 0x01, },
-       { 16 * 463.25 /*MHz*/, 0xc2, },
-       { 16 * 999.99        , 0xcf, },
+       { 16 * 140.25 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, },
+       { 16 * 999.99        , 0x8e, 0xcf, },
 };
 
 static struct tuner_params tuner_philips_pal_mk_params[] = {
@@ -639,16 +579,15 @@ static struct tuner_params tuner_philips_pal_mk_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_philips_pal_mk_pal_ranges,
                .count  = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
 
 static struct tuner_range tuner_philips_atsc_ranges[] = {
-       { 16 * 157.25 /*MHz*/, 0xa0, },
-       { 16 * 454.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_philips_atsc_params[] = {
@@ -656,16 +595,15 @@ static struct tuner_params tuner_philips_atsc_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_philips_atsc_ranges,
                .count  = ARRAY_SIZE(tuner_philips_atsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */
 
 static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x01, },
-       { 16 * 442.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
+       { 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_fm1236_mk3_params[] = {
@@ -673,25 +611,17 @@ static struct tuner_params tuner_fm1236_mk3_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_fm1236_mk3_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
-               .config = 0x8e,
                .cb_first_if_lower_freq = 1,
        },
 };
 
 /* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */
 
-static struct tuner_range tuner_philips_4in1_ntsc_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x01, },
-       { 16 * 442.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
-};
-
 static struct tuner_params tuner_philips_4in1_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_philips_4in1_ntsc_ranges,
-               .count  = ARRAY_SIZE(tuner_philips_4in1_ntsc_ranges),
-               .config = 0x8e,
+               .ranges = tuner_fm1236_mk3_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
        },
 };
 
@@ -702,16 +632,15 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_temic_4009f_5_pal_ranges,
                .count  = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */
 
 static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x01, },
-       { 16 * 454.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+       { 16 * 160.00 /*MHz*/, 0xce, 0x01, },
+       { 16 * 454.00 /*MHz*/, 0xce, 0x02, },
+       { 16 * 999.99        , 0xce, 0x08, },
 };
 
 static struct tuner_params tuner_panasonic_vp27_params[] = {
@@ -719,33 +648,25 @@ static struct tuner_params tuner_panasonic_vp27_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_panasonic_vp27_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
-               .config = 0xce,
        },
 };
 
 /* ------------ TUNER_LG_NTSC_TAPE - LGINNOTEK NTSC ------------ */
 
-static struct tuner_range tuner_lg_ntsc_tape_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x01, },
-       { 16 * 442.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
-};
-
 static struct tuner_params tuner_lg_ntsc_tape_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_lg_ntsc_tape_ranges,
-               .count  = ARRAY_SIZE(tuner_lg_ntsc_tape_ranges),
-               .config = 0x8e,
+               .ranges = tuner_fm1236_mk3_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
        },
 };
 
 /* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */
 
 static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = {
-       { 16 * 161.25 /*MHz*/, 0xa0, },
-       { 16 * 463.25 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
+       { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, },
+       { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
+       { 16 * 999.99        , 0x8e, 0x30, },
 };
 
 static struct tuner_params tuner_tnf_8831bgff_params[] = {
@@ -753,16 +674,15 @@ static struct tuner_params tuner_tnf_8831bgff_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_tnf_8831bgff_pal_ranges,
                .count  = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */
 
 static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = {
-       { 16 * 162.00 /*MHz*/, 0xa2, },
-       { 16 * 457.00 /*MHz*/, 0x94, },
-       { 16 * 999.99        , 0x31, },
+       { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, },
+       { 16 * 457.00 /*MHz*/, 0x8e, 0x94, },
+       { 16 * 999.99        , 0x8e, 0x31, },
 };
 
 static struct tuner_params tuner_microtune_4042fi5_params[] = {
@@ -770,7 +690,6 @@ static struct tuner_params tuner_microtune_4042fi5_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_microtune_4042fi5_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -778,9 +697,9 @@ static struct tuner_params tuner_microtune_4042fi5_params[] = {
 /* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */
 
 static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = {
-       { 16 * 172.00 /*MHz*/, 0x01, },
-       { 16 * 448.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+       { 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_tcl_2002n_params[] = {
@@ -788,34 +707,26 @@ static struct tuner_params tuner_tcl_2002n_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_tcl_2002n_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges),
-               .config = 0x8e,
                .cb_first_if_lower_freq = 1,
        },
 };
 
 /* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */
 
-static struct tuner_range tuner_philips_fm1256_ih3_pal_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x01, },
-       { 16 * 442.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
-};
-
 static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
-               .ranges = tuner_philips_fm1256_ih3_pal_ranges,
-               .count  = ARRAY_SIZE(tuner_philips_fm1256_ih3_pal_ranges),
-               .config = 0x8e,
+               .ranges = tuner_fm1236_mk3_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
        },
 };
 
 /* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */
 
 static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = {
-       { 16 * 157.25 /*MHz*/, 0x39, },
-       { 16 * 454.00 /*MHz*/, 0x3a, },
-       { 16 * 999.99        , 0x3c, },
+       { 16 * 157.25 /*MHz*/, 0x8e, 0x39, },
+       { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, },
+       { 16 * 999.99        , 0x8e, 0x3c, },
 };
 
 static struct tuner_params tuner_thomson_dtt7610_params[] = {
@@ -823,16 +734,15 @@ static struct tuner_params tuner_thomson_dtt7610_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_thomson_dtt7610_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */
 
 static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x41, },
-       { 16 * 454.00 /*MHz*/, 0x42, },
-       { 16 * 999.99        , 0x04, },
+       { 16 * 160.00 /*MHz*/, 0x8e, 0x41, },
+       { 16 * 454.00 /*MHz*/, 0x8e, 0x42, },
+       { 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_philips_fq1286_params[] = {
@@ -840,16 +750,15 @@ static struct tuner_params tuner_philips_fq1286_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_philips_fq1286_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */
 
 static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = {
-       { 16 * 170.00 /*MHz*/, 0x01, },
-       { 16 * 450.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+       { 16 * 170.00 /*MHz*/, 0xce, 0x01, },
+       { 16 * 450.00 /*MHz*/, 0xce, 0x02, },
+       { 16 * 999.99        , 0xce, 0x08, },
 };
 
 static struct tuner_params tuner_tcl_2002mb_params[] = {
@@ -857,24 +766,22 @@ static struct tuner_params tuner_tcl_2002mb_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_tcl_2002mb_pal_ranges,
                .count  = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges),
-               .config = 0xce,
        },
 };
 
 /* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */
 
-static struct tuner_range tuner_philips_fq12_6a___mk4_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x01, },
-       { 16 * 442.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
+static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = {
+       { 16 * 160.00 /*MHz*/, 0xce, 0x01, },
+       { 16 * 442.00 /*MHz*/, 0xce, 0x02, },
+       { 16 * 999.99        , 0xce, 0x04, },
 };
 
 static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
-               .ranges = tuner_philips_fq12_6a___mk4_ranges,
-               .count  = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_ranges),
-               .config = 0xce,
+               .ranges = tuner_philips_fq12_6a___mk4_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges),
        },
 };
 
@@ -883,35 +790,27 @@ static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
 static struct tuner_params tuner_philips_fq1236a_mk4_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_philips_fq12_6a___mk4_ranges,
-               .count  = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_ranges),
-               .config = 0x8e,
+               .ranges = tuner_fm1236_mk3_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
        },
 };
 
 /* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */
 
-static struct tuner_range tuner_ymec_tvf_8531mf_ntsc_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0xa0, },
-       { 16 * 454.00 /*MHz*/, 0x90, },
-       { 16 * 999.99        , 0x30, },
-};
-
 static struct tuner_params tuner_ymec_tvf_8531mf_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_ymec_tvf_8531mf_ntsc_ranges,
-               .count  = ARRAY_SIZE(tuner_ymec_tvf_8531mf_ntsc_ranges),
-               .config = 0x8e,
+               .ranges = tuner_philips_ntsc_m_ranges,
+               .count  = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
        },
 };
 
 /* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */
 
 static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x01, },
-       { 16 * 454.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
+       { 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 454.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
@@ -919,7 +818,6 @@ static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
@@ -928,9 +826,9 @@ static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
 /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
 
 static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = {
-       { 16 * 145.25 /*MHz*/, 0x39, },
-       { 16 * 415.25 /*MHz*/, 0x3a, },
-       { 16 * 999.99        , 0x3c, },
+       { 16 * 145.25 /*MHz*/, 0x8e, 0x39, },
+       { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, },
+       { 16 * 999.99        , 0x8e, 0x3c, },
 };
 
 
@@ -939,42 +837,39 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_thomson_dtt761x_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */
 
-static struct tuner_range tuner_tuner_tena_9533_di_pal_ranges[] = {
-       { 16 * 160.25 /*MHz*/, 0x01, },
-       { 16 * 464.25 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
+static struct tuner_range tuner_tena_9533_di_pal_ranges[] = {
+       { 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x04, },
 };
 
 static struct tuner_params tuner_tena_9533_di_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
-               .ranges = tuner_tuner_tena_9533_di_pal_ranges,
-               .count  = ARRAY_SIZE(tuner_tuner_tena_9533_di_pal_ranges),
-               .config = 0x8e,
+               .ranges = tuner_tena_9533_di_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
        },
 };
 
 /* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x51, },
-       { 16 * 442.00 /*MHz*/, 0x52, },
-       { 16 * 999.99        , 0x54, },
+       { 16 * 160.00 /*MHz*/, 0x86, 0x51, },
+       { 16 * 442.00 /*MHz*/, 0x86, 0x52, },
+       { 16 * 999.99        , 0x86, 0x54, },
 };
 
 
-static struct tuner_params tuner_tuner_philips_fmd1216me_mk3_params[] = {
+static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
                .count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
-               .config = 0x86,
        },
 };
 
@@ -982,9 +877,9 @@ static struct tuner_params tuner_tuner_philips_fmd1216me_mk3_params[] = {
 /* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
 
 static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0x01 },
-       { 16 * 455.00 /*MHz*/, 0x02 },
-       { 16 * 999.99        , 0x04 },
+       { 16 * 160.00 /*MHz*/, 0x8e, 0x01 },
+       { 16 * 455.00 /*MHz*/, 0x8e, 0x02 },
+       { 16 * 999.99        , 0x8e, 0x04 },
 };
 
 
@@ -993,50 +888,51 @@ static struct tuner_params tuner_tua6034_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_tua6034_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_tua6034_ntsc_ranges),
-               .config = 0x8e,
        },
 };
 
 /* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
 
-static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = {
-       { 16 * 160.25 /*MHz*/, 0x01, },
-       { 16 * 464.25 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
-};
-
 static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_PAL,
-               .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges,
-               .count  = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges),
-               .config = 0x8e,
+               .ranges = tuner_tena_9533_di_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
        },
 };
 
 /* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */
 
-static struct tuner_range tuner_lg_taln_mini_ntsc_ranges[] = {
-       { 16 * 137.25 /*MHz*/, 0x01, },
-       { 16 * 373.25 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+static struct tuner_range tuner_lg_taln_ntsc_ranges[] = {
+       { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 373.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
+};
+
+static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = {
+       { 16 * 150.00 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 425.00 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
 };
 
-static struct tuner_params tuner_lg_taln_mini_params[] = {
+static struct tuner_params tuner_lg_taln_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
-               .ranges = tuner_lg_taln_mini_ntsc_ranges,
-               .count  = ARRAY_SIZE(tuner_lg_taln_mini_ntsc_ranges),
-               .config = 0x8e,
+               .ranges = tuner_lg_taln_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges),
+       },{
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_lg_taln_pal_secam_ranges,
+               .count  = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges),
        },
 };
 
 /* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_td1316_pal_ranges[] = {
-       { 16 * 160.00 /*MHz*/, 0xa1, },
-       { 16 * 442.00 /*MHz*/, 0xa2, },
-       { 16 * 999.99        , 0xa4, },
+       { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, },
+       { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, },
+       { 16 * 999.99        , 0xc8, 0xa4, },
 };
 
 static struct tuner_params tuner_philips_td1316_params[] = {
@@ -1044,34 +940,42 @@ static struct tuner_params tuner_philips_td1316_params[] = {
                .type   = TUNER_PARAM_TYPE_PAL,
                .ranges = tuner_philips_td1316_pal_ranges,
                .count  = ARRAY_SIZE(tuner_philips_td1316_pal_ranges),
-               .config = 0xc8,
        },
 };
 
 /* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */
 
 static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = {
-       { 16 * 157.25 /*MHz*/, 0x01, },
-       { 16 * 454.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
+       { 16 * 157.25 /*MHz*/, 0xce, 0x01, },
+       { 16 * 454.00 /*MHz*/, 0xce, 0x02, },
+       { 16 * 999.99        , 0xce, 0x04, },
 };
 
 
-static struct tuner_params tuner_tuner_tuv1236d_params[] = {
+static struct tuner_params tuner_tuv1236d_params[] = {
        {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_tuv1236d_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges),
-               .config = 0xce,
        },
 };
 
-/* ------------ TUNER_TNF_5335MF - Philips NTSC ------------ */
+/* ------------ TUNER_TNF_xxx5  - Texas Instruments--------- */
+/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF
+ *     but it is expected to work also with other Tenna/Ymec
+ *     models based on TI SN 761677 chip on both PAL and NTSC
+ */
+
+static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = {
+       { 16 * 168.25 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 471.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
+};
 
 static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = {
-       { 16 * 157.25 /*MHz*/, 0x01, },
-       { 16 * 454.00 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x04, },
+       { 16 * 169.25 /*MHz*/, 0x8e, 0x01, },
+       { 16 * 469.25 /*MHz*/, 0x8e, 0x02, },
+       { 16 * 999.99        , 0x8e, 0x08, },
 };
 
 static struct tuner_params tuner_tnf_5335mf_params[] = {
@@ -1079,7 +983,11 @@ static struct tuner_params tuner_tnf_5335mf_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_tnf_5335mf_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges),
-               .config = 0x8e,
+       },
+       {
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_tnf_5335_d_if_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges),
        },
 };
 
@@ -1087,9 +995,9 @@ static struct tuner_params tuner_tnf_5335mf_params[] = {
 /* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */
 
 static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = {
-       { 16 * 175.75 /*MHz*/, 0x01, },
-       { 16 * 410.25 /*MHz*/, 0x02, },
-       { 16 * 999.99        , 0x08, },
+       { 16 * 130.00 /*MHz*/, 0xce, 0x01, },
+       { 16 * 364.50 /*MHz*/, 0xce, 0x02, },
+       { 16 * 999.99        , 0xce, 0x08, },
 };
 
 static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
@@ -1097,7 +1005,22 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
                .type   = TUNER_PARAM_TYPE_NTSC,
                .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
                .count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
-               .config = 0xce,
+       },
+};
+
+/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */
+
+static struct tuner_range tuner_thomson_fe6600_ranges[] = {
+       { 16 * 160.00 /*MHz*/, 0xfe, 0x11, },
+       { 16 * 442.00 /*MHz*/, 0xf6, 0x12, },
+       { 16 * 999.99        , 0xf6, 0x18, },
+};
+
+static struct tuner_params tuner_thomson_fe6600_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_thomson_fe6600_ranges,
+               .count  = ARRAY_SIZE(tuner_thomson_fe6600_ranges),
        },
 };
 
@@ -1108,18 +1031,22 @@ struct tunertype tuners[] = {
        [TUNER_TEMIC_PAL] = { /* TEMIC PAL */
                .name   = "Temic PAL (4002 FH5)",
                .params = tuner_temic_pal_params,
+               .count  = ARRAY_SIZE(tuner_temic_pal_params),
        },
        [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
                .name   = "Philips PAL_I (FI1246 and compatibles)",
                .params = tuner_philips_pal_i_params,
+               .count  = ARRAY_SIZE(tuner_philips_pal_i_params),
        },
        [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
                .name   = "Philips NTSC (FI1236,FM1236 and compatibles)",
                .params = tuner_philips_ntsc_params,
+               .count  = ARRAY_SIZE(tuner_philips_ntsc_params),
        },
        [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
                .name   = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
                .params = tuner_philips_secam_params,
+               .count  = ARRAY_SIZE(tuner_philips_secam_params),
        },
        [TUNER_ABSENT] = { /* Tuner Absent */
                .name   = "NoTuner",
@@ -1127,120 +1054,148 @@ struct tunertype tuners[] = {
        [TUNER_PHILIPS_PAL] = { /* Philips PAL */
                .name   = "Philips PAL_BG (FI1216 and compatibles)",
                .params = tuner_philips_pal_params,
+               .count  = ARRAY_SIZE(tuner_philips_pal_params),
        },
        [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
                .name   = "Temic NTSC (4032 FY5)",
                .params = tuner_temic_ntsc_params,
+               .count  = ARRAY_SIZE(tuner_temic_ntsc_params),
        },
        [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
                .name   = "Temic PAL_I (4062 FY5)",
                .params = tuner_temic_pal_i_params,
+               .count  = ARRAY_SIZE(tuner_temic_pal_i_params),
        },
        [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
                .name   = "Temic NTSC (4036 FY5)",
                .params = tuner_temic_4036fy5_ntsc_params,
+               .count  = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params),
        },
        [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
                .name   = "Alps HSBH1",
                .params = tuner_alps_tsbh1_ntsc_params,
+               .count  = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params),
        },
 
        /* 10-19 */
        [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
                .name   = "Alps TSBE1",
                .params = tuner_alps_tsb_1_params,
+               .count  = ARRAY_SIZE(tuner_alps_tsb_1_params),
        },
        [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
                .name   = "Alps TSBB5",
                .params = tuner_alps_tsbb5_params,
+               .count  = ARRAY_SIZE(tuner_alps_tsbb5_params),
        },
        [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
                .name   = "Alps TSBE5",
                .params = tuner_alps_tsbe5_params,
+               .count  = ARRAY_SIZE(tuner_alps_tsbe5_params),
        },
        [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
                .name   = "Alps TSBC5",
                .params = tuner_alps_tsbc5_params,
+               .count  = ARRAY_SIZE(tuner_alps_tsbc5_params),
        },
        [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
                .name   = "Temic PAL_BG (4006FH5)",
                .params = tuner_temic_4006fh5_params,
+               .count  = ARRAY_SIZE(tuner_temic_4006fh5_params),
        },
        [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
                .name   = "Alps TSCH6",
                .params = tuner_alps_tshc6_params,
+               .count  = ARRAY_SIZE(tuner_alps_tshc6_params),
        },
        [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
                .name   = "Temic PAL_DK (4016 FY5)",
                .params = tuner_temic_pal_dk_params,
+               .count  = ARRAY_SIZE(tuner_temic_pal_dk_params),
        },
        [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
                .name   = "Philips NTSC_M (MK2)",
                .params = tuner_philips_ntsc_m_params,
+               .count  = ARRAY_SIZE(tuner_philips_ntsc_m_params),
        },
        [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
                .name   = "Temic PAL_I (4066 FY5)",
                .params = tuner_temic_4066fy5_pal_i_params,
+               .count  = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params),
        },
        [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
                .name   = "Temic PAL* auto (4006 FN5)",
                .params = tuner_temic_4006fn5_multi_params,
+               .count  = ARRAY_SIZE(tuner_temic_4006fn5_multi_params),
        },
 
        /* 20-29 */
        [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
                .name   = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
                .params = tuner_temic_4009f_5_params,
+               .count  = ARRAY_SIZE(tuner_temic_4009f_5_params),
        },
        [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
                .name   = "Temic NTSC (4039 FR5)",
                .params = tuner_temic_4039fr5_params,
+               .count  = ARRAY_SIZE(tuner_temic_4039fr5_params),
        },
        [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
                .name   = "Temic PAL/SECAM multi (4046 FM5)",
                .params = tuner_temic_4046fm5_params,
+               .count  = ARRAY_SIZE(tuner_temic_4046fm5_params),
        },
        [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
                .name   = "Philips PAL_DK (FI1256 and compatibles)",
                .params = tuner_philips_pal_dk_params,
+               .count  = ARRAY_SIZE(tuner_philips_pal_dk_params),
        },
        [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
                .name   = "Philips PAL/SECAM multi (FQ1216ME)",
                .params = tuner_philips_fq1216me_params,
+               .count  = ARRAY_SIZE(tuner_philips_fq1216me_params),
        },
        [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
                .name   = "LG PAL_I+FM (TAPC-I001D)",
                .params = tuner_lg_pal_i_fm_params,
+               .count  = ARRAY_SIZE(tuner_lg_pal_i_fm_params),
        },
        [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
                .name   = "LG PAL_I (TAPC-I701D)",
                .params = tuner_lg_pal_i_params,
+               .count  = ARRAY_SIZE(tuner_lg_pal_i_params),
        },
        [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
                .name   = "LG NTSC+FM (TPI8NSR01F)",
                .params = tuner_lg_ntsc_fm_params,
+               .count  = ARRAY_SIZE(tuner_lg_ntsc_fm_params),
        },
        [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
                .name   = "LG PAL_BG+FM (TPI8PSB01D)",
                .params = tuner_lg_pal_fm_params,
+               .count  = ARRAY_SIZE(tuner_lg_pal_fm_params),
        },
        [TUNER_LG_PAL] = { /* LGINNOTEK PAL */
                .name   = "LG PAL_BG (TPI8PSB11D)",
                .params = tuner_lg_pal_params,
+               .count  = ARRAY_SIZE(tuner_lg_pal_params),
        },
 
        /* 30-39 */
        [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
                .name   = "Temic PAL* auto + FM (4009 FN5)",
                .params = tuner_temic_4009_fn5_multi_pal_fm_params,
+               .count  = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params),
        },
        [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
                .name   = "SHARP NTSC_JP (2U5JF5540)",
                .params = tuner_sharp_2u5jf5540_params,
+               .count  = ARRAY_SIZE(tuner_sharp_2u5jf5540_params),
        },
        [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
                .name   = "Samsung PAL TCPM9091PD27",
                .params = tuner_samsung_pal_tcpm9091pd27_params,
+               .count  = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params),
        },
        [TUNER_MT2032] = { /* Microtune PAL|NTSC */
                .name   = "MT20xx universal",
@@ -1248,86 +1203,106 @@ struct tunertype tuners[] = {
        [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
                .name   = "Temic PAL_BG (4106 FH5)",
                .params = tuner_temic_4106fh5_params,
+               .count  = ARRAY_SIZE(tuner_temic_4106fh5_params),
        },
        [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
                .name   = "Temic PAL_DK/SECAM_L (4012 FY5)",
                .params = tuner_temic_4012fy5_params,
+               .count  = ARRAY_SIZE(tuner_temic_4012fy5_params),
        },
        [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
                .name   = "Temic NTSC (4136 FY5)",
                .params = tuner_temic_4136_fy5_params,
+               .count  = ARRAY_SIZE(tuner_temic_4136_fy5_params),
        },
        [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
                .name   = "LG PAL (newer TAPC series)",
                .params = tuner_lg_pal_new_tapc_params,
+               .count  = ARRAY_SIZE(tuner_lg_pal_new_tapc_params),
        },
        [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
                .name   = "Philips PAL/SECAM multi (FM1216ME MK3)",
                .params = tuner_fm1216me_mk3_params,
+               .count  = ARRAY_SIZE(tuner_fm1216me_mk3_params),
        },
        [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
                .name   = "LG NTSC (newer TAPC series)",
                .params = tuner_lg_ntsc_new_tapc_params,
+               .count  = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params),
        },
 
        /* 40-49 */
        [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
                .name   = "HITACHI V7-J180AT",
                .params = tuner_hitachi_ntsc_params,
+               .count  = ARRAY_SIZE(tuner_hitachi_ntsc_params),
        },
        [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
                .name   = "Philips PAL_MK (FI1216 MK)",
                .params = tuner_philips_pal_mk_params,
+               .count  = ARRAY_SIZE(tuner_philips_pal_mk_params),
        },
        [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
                .name   = "Philips 1236D ATSC/NTSC dual in",
                .params = tuner_philips_atsc_params,
+               .count  = ARRAY_SIZE(tuner_philips_atsc_params),
        },
        [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
                .name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
                .params = tuner_fm1236_mk3_params,
+               .count  = ARRAY_SIZE(tuner_fm1236_mk3_params),
        },
        [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
                .name   = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
                .params = tuner_philips_4in1_params,
+               .count  = ARRAY_SIZE(tuner_philips_4in1_params),
        },
        [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
                .name   = "Microtune 4049 FM5",
                .params = tuner_microtune_4049_fm5_params,
+               .count  = ARRAY_SIZE(tuner_microtune_4049_fm5_params),
        },
        [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
                .name   = "Panasonic VP27s/ENGE4324D",
                .params = tuner_panasonic_vp27_params,
+               .count  = ARRAY_SIZE(tuner_panasonic_vp27_params),
        },
        [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
                .name   = "LG NTSC (TAPE series)",
                .params = tuner_lg_ntsc_tape_params,
+               .count  = ARRAY_SIZE(tuner_lg_ntsc_tape_params),
        },
        [TUNER_TNF_8831BGFF] = { /* Philips PAL */
                .name   = "Tenna TNF 8831 BGFF)",
                .params = tuner_tnf_8831bgff_params,
+               .count  = ARRAY_SIZE(tuner_tnf_8831bgff_params),
        },
        [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
                .name   = "Microtune 4042 FI5 ATSC/NTSC dual in",
                .params = tuner_microtune_4042fi5_params,
+               .count  = ARRAY_SIZE(tuner_microtune_4042fi5_params),
        },
 
        /* 50-59 */
        [TUNER_TCL_2002N] = { /* TCL NTSC */
                .name   = "TCL 2002N",
                .params = tuner_tcl_2002n_params,
+               .count  = ARRAY_SIZE(tuner_tcl_2002n_params),
        },
        [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
                .name   = "Philips PAL/SECAM_D (FM 1256 I-H3)",
                .params = tuner_philips_fm1256_ih3_params,
+               .count  = ARRAY_SIZE(tuner_philips_fm1256_ih3_params),
        },
        [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
                .name   = "Thomson DTT 7610 (ATSC/NTSC)",
                .params = tuner_thomson_dtt7610_params,
+               .count  = ARRAY_SIZE(tuner_thomson_dtt7610_params),
        },
        [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
                .name   = "Philips FQ1286",
                .params = tuner_philips_fq1286_params,
+               .count  = ARRAY_SIZE(tuner_philips_fq1286_params),
        },
        [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
                .name   = "tda8290+75",
@@ -1335,22 +1310,27 @@ struct tunertype tuners[] = {
        [TUNER_TCL_2002MB] = { /* TCL PAL */
                .name   = "TCL 2002MB",
                .params = tuner_tcl_2002mb_params,
+               .count  = ARRAY_SIZE(tuner_tcl_2002mb_params),
        },
        [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
                .name   = "Philips PAL/SECAM multi (FQ1216AME MK4)",
                .params = tuner_philips_fq1216ame_mk4_params,
+               .count  = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params),
        },
        [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
                .name   = "Philips FQ1236A MK4",
                .params = tuner_philips_fq1236a_mk4_params,
+               .count  = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params),
        },
        [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
                .name   = "Ymec TVision TVF-8531MF/8831MF/8731MF",
                .params = tuner_ymec_tvf_8531mf_params,
+               .count  = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params),
        },
        [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
                .name   = "Ymec TVision TVF-5533MF",
                .params = tuner_ymec_tvf_5533mf_params,
+               .count  = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params),
        },
 
        /* 60-69 */
@@ -1358,10 +1338,12 @@ struct tunertype tuners[] = {
                /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
                .name   = "Thomson DTT 761X (ATSC/NTSC)",
                .params = tuner_thomson_dtt761x_params,
+               .count  = ARRAY_SIZE(tuner_thomson_dtt761x_params),
        },
        [TUNER_TENA_9533_DI] = { /* Philips PAL */
                .name   = "Tena TNF9533-D/IF/TNF9533-B/DF",
                .params = tuner_tena_9533_di_params,
+               .count  = ARRAY_SIZE(tuner_tena_9533_di_params),
        },
        [TUNER_TEA5767] = { /* Philips RADIO */
                .name   = "Philips TEA5767HN FM Radio",
@@ -1369,37 +1351,54 @@ struct tunertype tuners[] = {
        },
        [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
                .name   = "Philips FMD1216ME MK3 Hybrid Tuner",
-               .params = tuner_tuner_philips_fmd1216me_mk3_params,
+               .params = tuner_philips_fmd1216me_mk3_params,
+               .count  = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
        },
        [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
                .name   = "LG TDVS-H062F/TUA6034",
                .params = tuner_tua6034_params,
+               .count  = ARRAY_SIZE(tuner_tua6034_params),
        },
        [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
                .name   = "Ymec TVF66T5-B/DFF",
                .params = tuner_ymec_tvf66t5_b_dff_params,
+               .count  = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params),
        },
-       [TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */
-               .name   = "LG NTSC (TALN mini series)",
-               .params = tuner_lg_taln_mini_params,
+       [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */
+               .name   = "LG TALN series",
+               .params = tuner_lg_taln_params,
+               .count  = ARRAY_SIZE(tuner_lg_taln_params),
        },
        [TUNER_PHILIPS_TD1316] = { /* Philips PAL */
                .name   = "Philips TD1316 Hybrid Tuner",
                .params = tuner_philips_td1316_params,
+               .count  = ARRAY_SIZE(tuner_philips_td1316_params),
        },
        [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
                .name   = "Philips TUV1236D ATSC/NTSC dual in",
-               .params = tuner_tuner_tuv1236d_params,
+               .params = tuner_tuv1236d_params,
+               .count  = ARRAY_SIZE(tuner_tuv1236d_params),
        },
-       [TUNER_TNF_5335MF] = { /* Philips NTSC */
-               .name   = "Tena TNF 5335 MF",
+       [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */
+               .name   = "Tena TNF 5335 and similar models",
                .params = tuner_tnf_5335mf_params,
+               .count  = ARRAY_SIZE(tuner_tnf_5335mf_params),
        },
 
        /* 70-79 */
        [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */
                .name   = "Samsung TCPN 2121P30A",
                .params = tuner_samsung_tcpn_2121p30a_params,
+               .count  = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
+       },
+       [TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */
+               .name   = "Xceive xc3028",
+               /* see xc3028.c for details */
+       },
+       [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
+               .name   = "Thomson FE6600",
+               .params = tuner_thomson_fe6600_params,
+               .count  = ARRAY_SIZE(tuner_thomson_fe6600_params),
        },
 };
 
index c8e5ad0..4efb01b 100644 (file)
@@ -130,6 +130,7 @@ struct CHIPSTATE {
        struct timer_list    wt;
        int                  done;
        int                  watch_stereo;
+       int                  audmode;
 };
 
 /* ---------------------------------------------------------------------- */
@@ -1514,6 +1515,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
        chip->type = desc-chiplist;
        chip->shadow.count = desc->registers+1;
        chip->prevmode = -1;
+       chip->audmode = V4L2_TUNER_MODE_LANG1;
        /* register */
        i2c_attach_client(&chip->c);
 
@@ -1671,6 +1673,8 @@ static int chip_command(struct i2c_client *client,
                struct v4l2_tuner *vt = arg;
                int mode = 0;
 
+               if (chip->radio)
+                       break;
                switch (vt->audmode) {
                case V4L2_TUNER_MODE_MONO:
                        mode = VIDEO_SOUND_MONO;
@@ -1685,8 +1689,9 @@ static int chip_command(struct i2c_client *client,
                        mode = VIDEO_SOUND_LANG2;
                        break;
                default:
-                       break;
+                       return -EINVAL;
                }
+               chip->audmode = vt->audmode;
 
                if (desc->setmode && mode) {
                        chip->watch_stereo = 0;
@@ -1704,7 +1709,7 @@ static int chip_command(struct i2c_client *client,
 
                if (chip->radio)
                        break;
-               vt->audmode = 0;
+               vt->audmode = chip->audmode;
                vt->rxsubchans = 0;
                vt->capability = V4L2_TUNER_CAP_STEREO |
                        V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
@@ -1716,19 +1721,12 @@ static int chip_command(struct i2c_client *client,
                        vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
                if (mode & VIDEO_SOUND_STEREO)
                        vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+               /* Note: for SAP it should be mono/lang2 or stereo/lang2.
+                  When this module is converted fully to v4l2, then this
+                  should change for those chips that can detect SAP. */
                if (mode & VIDEO_SOUND_LANG1)
-                       vt->rxsubchans |= V4L2_TUNER_SUB_LANG1 |
-                                         V4L2_TUNER_SUB_LANG2;
-
-               mode = chip->mode;
-               if (mode & VIDEO_SOUND_MONO)
-                       vt->audmode = V4L2_TUNER_MODE_MONO;
-               if (mode & VIDEO_SOUND_STEREO)
-                       vt->audmode = V4L2_TUNER_MODE_STEREO;
-               if (mode & VIDEO_SOUND_LANG1)
-                       vt->audmode = V4L2_TUNER_MODE_LANG1;
-               if (mode & VIDEO_SOUND_LANG2)
-                       vt->audmode = V4L2_TUNER_MODE_LANG2;
+                       vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
+                                        V4L2_TUNER_SUB_LANG2;
                break;
        }
 
index 1864423..69d0fe1 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * tvp5150 - Texas Instruments TVP5150A(M) video decoder driver
+ * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver
  *
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
- * This code is placed under the terms of the GNU General Public License
+ * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
  */
 
 #include <linux/i2c.h>
 
 #include "tvp5150_reg.h"
 
-MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); /* standard i2c insmod options */
+MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
 
+/* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
        0xb8 >> 1,
        0xba >> 1,
@@ -29,6 +30,9 @@ static int debug = 0;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
+#define tvp5150_err(fmt, arg...) do { \
+       printk(KERN_ERR "%s %d-%04x: " fmt, c->driver->driver.name, \
+              i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
 #define tvp5150_info(fmt, arg...) do { \
        printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \
               i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
@@ -84,7 +88,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = {
 struct tvp5150 {
        struct i2c_client *client;
 
-       int norm;
+       v4l2_std_id norm;       /* Current set standard */
        int input;
        int enable;
        int bright;
@@ -125,310 +129,155 @@ static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
                tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
 }
 
+static void dump_reg_range(struct i2c_client *c, char *s, u8 init, const u8 end,int max_line)
+{
+       int i=0;
+
+       while (init!=(u8)(end+1)) {
+               if ((i%max_line) == 0) {
+                       if (i>0)
+                               printk("\n");
+                       printk("tvp5150: %s reg 0x%02x = ",s,init);
+               }
+               printk("%02x ",tvp5150_read(c, init));
+
+               init++;
+               i++;
+       }
+       printk("\n");
+}
+
 static void dump_reg(struct i2c_client *c)
 {
        printk("tvp5150: Video input source selection #1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+                                       tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
        printk("tvp5150: Analog channel controls = 0x%02x\n",
-              tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+                                       tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
        printk("tvp5150: Operation mode controls = 0x%02x\n",
-              tvp5150_read(c, TVP5150_OP_MODE_CTL));
+                                       tvp5150_read(c, TVP5150_OP_MODE_CTL));
        printk("tvp5150: Miscellaneous controls = 0x%02x\n",
-              tvp5150_read(c, TVP5150_MISC_CTL));
-       printk("tvp5150: Autoswitch mask: TVP5150A / TVP5150AM = 0x%02x\n",
-              tvp5150_read(c, TVP5150_AUTOSW_MSK));
+                                       tvp5150_read(c, TVP5150_MISC_CTL));
+       printk("tvp5150: Autoswitch mask= 0x%02x\n",
+                                       tvp5150_read(c, TVP5150_AUTOSW_MSK));
        printk("tvp5150: Color killer threshold control = 0x%02x\n",
-              tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
-       printk("tvp5150: Luminance processing control #1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1));
-       printk("tvp5150: Luminance processing control #2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2));
+                                       tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+       printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
+                                       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1),
+                                       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2),
+                                       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
        printk("tvp5150: Brightness control = 0x%02x\n",
-              tvp5150_read(c, TVP5150_BRIGHT_CTL));
+                                       tvp5150_read(c, TVP5150_BRIGHT_CTL));
        printk("tvp5150: Color saturation control = 0x%02x\n",
-              tvp5150_read(c, TVP5150_SATURATION_CTL));
+                                       tvp5150_read(c, TVP5150_SATURATION_CTL));
        printk("tvp5150: Hue control = 0x%02x\n",
-              tvp5150_read(c, TVP5150_HUE_CTL));
+                                       tvp5150_read(c, TVP5150_HUE_CTL));
        printk("tvp5150: Contrast control = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CONTRAST_CTL));
+                                       tvp5150_read(c, TVP5150_CONTRAST_CTL));
        printk("tvp5150: Outputs and data rates select = 0x%02x\n",
-              tvp5150_read(c, TVP5150_DATA_RATE_SEL));
-       printk("tvp5150: Luminance processing control #3 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+                                       tvp5150_read(c, TVP5150_DATA_RATE_SEL));
        printk("tvp5150: Configuration shared pins = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
-       printk("tvp5150: Active video cropping start MSB = 0x%02x\n",
-              tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB));
-       printk("tvp5150: Active video cropping start LSB = 0x%02x\n",
-              tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
-       printk("tvp5150: Active video cropping stop MSB = 0x%02x\n",
-              tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB));
-       printk("tvp5150: Active video cropping stop LSB = 0x%02x\n",
-              tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+                                       tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+       printk("tvp5150: Active video cropping start = 0x%02x%02x\n",
+                                       tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB),
+                                       tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+       printk("tvp5150: Active video cropping stop  = 0x%02x%02x\n",
+                                       tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB),
+                                       tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
        printk("tvp5150: Genlock/RTC = 0x%02x\n",
-              tvp5150_read(c, TVP5150_GENLOCK));
+                                       tvp5150_read(c, TVP5150_GENLOCK));
        printk("tvp5150: Horizontal sync start = 0x%02x\n",
-              tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+                                       tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
        printk("tvp5150: Vertical blanking start = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+                                       tvp5150_read(c, TVP5150_VERT_BLANKING_START));
        printk("tvp5150: Vertical blanking stop = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
-       printk("tvp5150: Chrominance processing control #1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1));
-       printk("tvp5150: Chrominance processing control #2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+                                       tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+       printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
+                                       tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1),
+                                       tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
        printk("tvp5150: Interrupt reset register B = 0x%02x\n",
-              tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+                                       tvp5150_read(c, TVP5150_INT_RESET_REG_B));
        printk("tvp5150: Interrupt enable register B = 0x%02x\n",
-              tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+                                       tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
        printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
-              tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+                                       tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
        printk("tvp5150: Video standard = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VIDEO_STD));
-       printk("tvp5150: Cb gain factor = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CB_GAIN_FACT));
-       printk("tvp5150: Cr gain factor = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+                                       tvp5150_read(c, TVP5150_VIDEO_STD));
+       printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
+                                       tvp5150_read(c, TVP5150_CB_GAIN_FACT),
+                                       tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
        printk("tvp5150: Macrovision on counter = 0x%02x\n",
-              tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+                                       tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
        printk("tvp5150: Macrovision off counter = 0x%02x\n",
-              tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
-       printk("tvp5150: revision select (TVP5150AM1 only) = 0x%02x\n",
-              tvp5150_read(c, TVP5150_REV_SELECT));
-       printk("tvp5150: MSB of device ID = 0x%02x\n",
-              tvp5150_read(c, TVP5150_MSB_DEV_ID));
-       printk("tvp5150: LSB of device ID = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LSB_DEV_ID));
-       printk("tvp5150: ROM major version = 0x%02x\n",
-              tvp5150_read(c, TVP5150_ROM_MAJOR_VER));
-       printk("tvp5150: ROM minor version = 0x%02x\n",
-              tvp5150_read(c, TVP5150_ROM_MINOR_VER));
-       printk("tvp5150: Vertical line count MSB = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB));
-       printk("tvp5150: Vertical line count LSB = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+                                       tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+       printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
+                                       (tvp5150_read(c, TVP5150_REV_SELECT)&1)?3:4);
+       printk("tvp5150: Device ID = %02x%02x\n",
+                                       tvp5150_read(c, TVP5150_MSB_DEV_ID),
+                                       tvp5150_read(c, TVP5150_LSB_DEV_ID));
+       printk("tvp5150: ROM version = (hex) %02x.%02x\n",
+                                       tvp5150_read(c, TVP5150_ROM_MAJOR_VER),
+                                       tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+       printk("tvp5150: Vertical line count = 0x%02x%02x\n",
+                                       tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB),
+                                       tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
        printk("tvp5150: Interrupt status register B = 0x%02x\n",
-              tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+                                       tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
        printk("tvp5150: Interrupt active register B = 0x%02x\n",
-              tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
-       printk("tvp5150: Status register #1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_STATUS_REG_1));
-       printk("tvp5150: Status register #2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_STATUS_REG_2));
-       printk("tvp5150: Status register #3 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_STATUS_REG_3));
-       printk("tvp5150: Status register #4 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_STATUS_REG_4));
-       printk("tvp5150: Status register #5 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_STATUS_REG_5));
-       printk("tvp5150: Closed caption data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CC_DATA_REG1));
-       printk("tvp5150: Closed caption data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CC_DATA_REG2));
-       printk("tvp5150: Closed caption data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CC_DATA_REG3));
-       printk("tvp5150: Closed caption data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CC_DATA_REG4));
-       printk("tvp5150: WSS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_WSS_DATA_REG1));
-       printk("tvp5150: WSS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_WSS_DATA_REG2));
-       printk("tvp5150: WSS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_WSS_DATA_REG3));
-       printk("tvp5150: WSS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_WSS_DATA_REG4));
-       printk("tvp5150: WSS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_WSS_DATA_REG5));
-       printk("tvp5150: WSS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_WSS_DATA_REG6));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG1));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG2));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG3));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG4));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG5));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG6));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG7));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG8));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG9));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG10));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG11));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG12));
-       printk("tvp5150: VPS data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VPS_DATA_REG13));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG1));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG2));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG3));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG4));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG5));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG6));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG7));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG8));
-       printk("tvp5150: VITC data registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VITC_DATA_REG9));
-       printk("tvp5150: VBI FIFO read data = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA));
-       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_1));
-       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_2));
-       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_3));
-       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_4));
-       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_5));
-       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_1));
-       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_2));
-       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_3));
-       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_4));
-       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_5));
+                                       tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+       printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
+                                       tvp5150_read(c, TVP5150_STATUS_REG_1),
+                                       tvp5150_read(c, TVP5150_STATUS_REG_2),
+                                       tvp5150_read(c, TVP5150_STATUS_REG_3),
+                                       tvp5150_read(c, TVP5150_STATUS_REG_4),
+                                       tvp5150_read(c, TVP5150_STATUS_REG_5));
+
+       dump_reg_range(c,"Teletext filter 1",   TVP5150_TELETEXT_FIL1_INI,
+                                               TVP5150_TELETEXT_FIL1_END,8);
+       dump_reg_range(c,"Teletext filter 2",   TVP5150_TELETEXT_FIL2_INI,
+                                               TVP5150_TELETEXT_FIL2_END,8);
+
        printk("tvp5150: Teletext filter enable = 0x%02x\n",
-              tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+                                       tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
        printk("tvp5150: Interrupt status register A = 0x%02x\n",
-              tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+                                       tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
        printk("tvp5150: Interrupt enable register A = 0x%02x\n",
-              tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+                                       tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
        printk("tvp5150: Interrupt configuration = 0x%02x\n",
-              tvp5150_read(c, TVP5150_INT_CONF));
-       printk("tvp5150: VDP configuration RAM data = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VDP_CONF_RAM_DATA));
-       printk("tvp5150: Configuration RAM address low byte = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CONF_RAM_ADDR_LOW));
-       printk("tvp5150: Configuration RAM address high byte = 0x%02x\n",
-              tvp5150_read(c, TVP5150_CONF_RAM_ADDR_HIGH));
+                                       tvp5150_read(c, TVP5150_INT_CONF));
        printk("tvp5150: VDP status register = 0x%02x\n",
-              tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+                                       tvp5150_read(c, TVP5150_VDP_STATUS_REG));
        printk("tvp5150: FIFO word count = 0x%02x\n",
-              tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+                                       tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
        printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
-              tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+                                       tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
        printk("tvp5150: FIFO reset = 0x%02x\n",
-              tvp5150_read(c, TVP5150_FIFO_RESET));
+                                       tvp5150_read(c, TVP5150_FIFO_RESET));
        printk("tvp5150: Line number interrupt = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
-       printk("tvp5150: Pixel alignment register low byte = 0x%02x\n",
-              tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
-       printk("tvp5150: Pixel alignment register high byte = 0x%02x\n",
-              tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH));
+                                       tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+       printk("tvp5150: Pixel alignment register = 0x%02x%02x\n",
+                                       tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH),
+                                       tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
        printk("tvp5150: FIFO output control = 0x%02x\n",
-              tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
-       printk("tvp5150: Full field enable 1 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_FULL_FIELD_ENA_1));
-       printk("tvp5150: Full field enable 2 = 0x%02x\n",
-              tvp5150_read(c, TVP5150_FULL_FIELD_ENA_2));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_1));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_2));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_3));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_4));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_5));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_6));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_7));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_8));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_9));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_10));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_11));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_12));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_13));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_14));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_15));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_16));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_17));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_18));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_19));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_20));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_21));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_22));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_23));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_24));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_25));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_27));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_28));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_29));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_30));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_31));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_32));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_33));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_34));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_35));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_36));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_37));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_38));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_39));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_40));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_41));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_42));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_43));
-       printk("tvp5150: Line mode registers = 0x%02x\n",
-              tvp5150_read(c, TVP5150_LINE_MODE_REG_44));
+                                       tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+       printk("tvp5150: Full field enable = 0x%02x\n",
+                                       tvp5150_read(c, TVP5150_FULL_FIELD_ENA));
        printk("tvp5150: Full field mode register = 0x%02x\n",
-              tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+                                       tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+
+       dump_reg_range(c,"CC   data",   TVP5150_CC_DATA_INI,
+                                       TVP5150_CC_DATA_END,8);
+
+       dump_reg_range(c,"WSS  data",   TVP5150_WSS_DATA_INI,
+                                       TVP5150_WSS_DATA_END,8);
+
+       dump_reg_range(c,"VPS  data",   TVP5150_VPS_DATA_INI,
+                                       TVP5150_VPS_DATA_END,8);
+
+       dump_reg_range(c,"VITC data",   TVP5150_VITC_DATA_INI,
+                                       TVP5150_VITC_DATA_END,10);
+
+       dump_reg_range(c,"Line mode",   TVP5150_LINE_MODE_INI,
+                                       TVP5150_LINE_MODE_END,8);
 }
 
 /****************************************************************************
@@ -593,10 +442,10 @@ static const struct i2c_reg_value tvp5150_init_default[] = {
                TVP5150_FIFO_OUT_CTRL,0x01
        },
        { /* 0xcf */
-               TVP5150_FULL_FIELD_ENA_1,0x00
+               TVP5150_FULL_FIELD_ENA,0x00
        },
        { /* 0xd0 */
-               TVP5150_FULL_FIELD_ENA_2,0x00
+               TVP5150_LINE_MODE_INI,0x00
        },
        { /* 0xfc */
                TVP5150_FULL_FIELD_MODE_REG,0x7f
@@ -629,54 +478,101 @@ static const struct i2c_reg_value tvp5150_init_enable[] = {
        }
 };
 
+struct tvp5150_vbi_type {
+       unsigned int vbi_type;
+       unsigned int ini_line;
+       unsigned int end_line;
+       unsigned int by_field :1;
+};
+
 struct i2c_vbi_ram_value {
        u16 reg;
-       unsigned char values[26];
+       struct tvp5150_vbi_type type;
+       unsigned char values[16];
 };
 
+/* This struct have the values for each supported VBI Standard
+ * by
+ tvp5150_vbi_types should follow the same order as vbi_ram_default
+ * value 0 means rom position 0x10, value 1 means rom position 0x30
+ * and so on. There are 16 possible locations from 0 to 15.
+ */
+
 static struct i2c_vbi_ram_value vbi_ram_default[] =
 {
-       {0x010, /* WST SECAM 6 */
-               { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       {0x010, /* Teletext, SECAM, WST System A */
+               {V4L2_SLICED_TELETEXT_SECAM,6,23,1},
+               { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
+                 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
-       {0x030, /* WST PAL B 6 */
-               { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       {0x030, /* Teletext, PAL, WST System B */
+               {V4L2_SLICED_TELETEXT_PAL_B,6,22,1},
+               { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
+                 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
-       {0x050, /* WST PAL C 6 */
-               { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       {0x050, /* Teletext, PAL, WST System C */
+               {V4L2_SLICED_TELETEXT_PAL_C,6,22,1},
+               { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
+                 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
-       {0x070, /* WST NTSC 6 */
-               { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       {0x070, /* Teletext, NTSC, WST System B */
+               {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1},
+               { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
+                 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
-       {0x090, /* NABTS, NTSC 6 */
-               { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x15, 0x0 }
+       {0x090, /* Tetetext, NTSC NABTS System C */
+               {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1},
+               { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
+                 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
        },
-       {0x0b0, /* NABTS, NTSC-J 6 */
-               { 0xaa, 0xaa, 0xff, 0xff , 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 }
+       {0x0b0, /* Teletext, NTSC-J, NABTS System D */
+               {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1},
+               { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
+                 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
-       {0x0d0, /* CC, PAL/SECAM 6 */
-               { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+       {0x0d0, /* Closed Caption, PAL/SECAM */
+               {V4L2_SLICED_CAPTION_625,22,22,1},
+               { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
+                 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
        },
-       {0x0f0, /* CC, NTSC 6 */
-               { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 }
+       {0x0f0, /* Closed Caption, NTSC */
+               {V4L2_SLICED_CAPTION_525,21,21,1},
+               { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
+                 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
        },
-       {0x110, /* WSS, PAL/SECAM 6 */
-               { 0x5b, 0x55, 0xc5, 0xff , 0x0, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x0, 0x0, 0x0, 0x3a, 0x0 }
+       {0x110, /* Wide Screen Signal, PAL/SECAM */
+               {V4L2_SLICED_WSS_625,23,23,1},
+               { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
+                 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
        },
-       {0x130, /* WSS, NTSC C */
-               { 0x38, 0x00, 0x3f, 0x00 , 0x0, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x0, 0x0, 0x0, 0x39, 0x0 }
+       {0x130, /* Wide Screen Signal, NTSC C */
+               {V4L2_SLICED_WSS_525,20,20,1},
+               { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
+                 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
        },
-       {0x150, /* VITC, PAL/SECAM 6 */
-               { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+       {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
+               {V4l2_SLICED_VITC_625,6,22,0},
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
+                 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
        },
-       {0x170, /* VITC, NTSC 6 */
-               { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 }
+       {0x170, /* Vertical Interval Timecode (VITC), NTSC */
+               {V4l2_SLICED_VITC_525,10,20,0},
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
+                 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
        },
+       {0x190, /* Video Program System (VPS), PAL */
+               {V4L2_SLICED_VPS,16,16,0},
+               { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
+                 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
+       },
+       /* 0x1d0 User programmable */
+
+       /* End of struct */
        { (u16)-1 }
 };
 
 static int tvp5150_write_inittab(struct i2c_client *c,
-                                const struct i2c_reg_value *regs)
+                               const struct i2c_reg_value *regs)
 {
        while (regs->reg != 0xff) {
                tvp5150_write(c, regs->reg, regs->value);
@@ -686,15 +582,15 @@ static int tvp5150_write_inittab(struct i2c_client *c,
 }
 
 static int tvp5150_vdp_init(struct i2c_client *c,
-                                const struct i2c_vbi_ram_value *regs)
+                               const struct i2c_vbi_ram_value *regs)
 {
        unsigned int i;
 
        /* Disable Full Field */
-       tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0);
+       tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
 
        /* Before programming, Line mode should be at 0xff */
-       for (i=TVP5150_FULL_FIELD_ENA_2; i<=TVP5150_LINE_MODE_REG_44; i++)
+       for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
                tvp5150_write(c, i, 0xff);
 
        /* Load Ram Table */
@@ -710,6 +606,117 @@ static int tvp5150_vdp_init(struct i2c_client *c,
        return 0;
 }
 
+/* Fills VBI capabilities based on i2c_vbi_ram_value struct */
+static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
+                               struct v4l2_sliced_vbi_cap *cap)
+{
+       int line;
+
+       memset(cap, 0, sizeof *cap);
+
+       while (regs->reg != (u16)-1 ) {
+               for (line=regs->type.ini_line;line<=regs->type.end_line;line++) {
+                       cap->service_lines[0][line] |= regs->type.vbi_type;
+               }
+               cap->service_set |= regs->type.vbi_type;
+
+               regs++;
+       }
+}
+
+/* Set vbi processing
+ * type - one of tvp5150_vbi_types
+ * line - line to gather data
+ * fields: bit 0 field1, bit 1, field2
+ * flags (default=0xf0) is a bitmask, were set means:
+ *     bit 7: enable filtering null bytes on CC
+ *     bit 6: send data also to FIFO
+ *     bit 5: don't allow data with errors on FIFO
+ *     bit 4: enable ECC when possible
+ * pix_align = pix alignment:
+ *     LSB = field1
+ *     MSB = field2
+ */
+static int tvp5150_set_vbi(struct i2c_client *c,
+                       const struct i2c_vbi_ram_value *regs,
+                       unsigned int type,u8 flags, int line,
+                       const int fields)
+{
+       struct tvp5150 *decoder = i2c_get_clientdata(c);
+       v4l2_std_id std=decoder->norm;
+       u8 reg;
+       int pos=0;
+
+       if (std == V4L2_STD_ALL) {
+               tvp5150_err("VBI can't be configured without knowing number of lines\n");
+               return 0;
+       } else if (std && V4L2_STD_625_50) {
+               /* Don't follow NTSC Line number convension */
+               line += 3;
+       }
+
+       if (line<6||line>27)
+               return 0;
+
+       while (regs->reg != (u16)-1 ) {
+               if ((type & regs->type.vbi_type) &&
+                   (line>=regs->type.ini_line) &&
+                   (line<=regs->type.end_line)) {
+                       type=regs->type.vbi_type;
+                       break;
+               }
+
+               regs++;
+               pos++;
+       }
+       if (regs->reg == (u16)-1)
+               return 0;
+
+       type=pos | (flags & 0xf0);
+       reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+
+       if (fields&1) {
+               tvp5150_write(c, reg, type);
+       }
+
+       if (fields&2) {
+               tvp5150_write(c, reg+1, type);
+       }
+
+       return type;
+}
+
+static int tvp5150_get_vbi(struct i2c_client *c,
+                       const struct i2c_vbi_ram_value *regs, int line)
+{
+       struct tvp5150 *decoder = i2c_get_clientdata(c);
+       v4l2_std_id std=decoder->norm;
+       u8 reg;
+       int pos, type=0;
+
+       if (std == V4L2_STD_ALL) {
+               tvp5150_err("VBI can't be configured without knowing number of lines\n");
+               return 0;
+       } else if (std && V4L2_STD_625_50) {
+               /* Don't follow NTSC Line number convension */
+               line += 3;
+       }
+
+       if (line<6||line>27)
+               return 0;
+
+       reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+
+       pos=tvp5150_read(c, reg)&0x0f;
+       if (pos<0x0f)
+               type=regs[pos].type.vbi_type;
+
+       pos=tvp5150_read(c, reg+1)&0x0f;
+       if (pos<0x0f)
+               type|=regs[pos].type.vbi_type;
+
+       return type;
+}
 static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std)
 {
        struct tvp5150 *decoder = i2c_get_clientdata(c);
@@ -854,6 +861,69 @@ static int tvp5150_command(struct i2c_client *c,
                *(v4l2_std_id *)arg = decoder->norm;
                break;
 
+       case VIDIOC_G_SLICED_VBI_CAP:
+       {
+               struct v4l2_sliced_vbi_cap *cap = arg;
+               tvp5150_dbg(1, "VIDIOC_G_SLICED_VBI_CAP\n");
+
+               tvp5150_vbi_get_cap(vbi_ram_default, cap);
+               break;
+       }
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *fmt;
+               struct v4l2_sliced_vbi_format *svbi;
+               int i;
+
+               fmt = arg;
+               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+                       return -EINVAL;
+               svbi = &fmt->fmt.sliced;
+               if (svbi->service_set != 0) {
+                       for (i = 0; i <= 23; i++) {
+                               svbi->service_lines[1][i] = 0;
+
+                               svbi->service_lines[0][i]=tvp5150_set_vbi(c,
+                                        vbi_ram_default,
+                                        svbi->service_lines[0][i],0xf0,i,3);
+                       }
+                       /* Enables FIFO */
+                       tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,1);
+               } else {
+                       /* Disables FIFO*/
+                       tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,0);
+
+                       /* Disable Full Field */
+                       tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
+
+                       /* Disable Line modes */
+                       for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
+                               tvp5150_write(c, i, 0xff);
+               }
+               break;
+       }
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *fmt;
+               struct v4l2_sliced_vbi_format *svbi;
+
+               int i, mask=0;
+
+               fmt = arg;
+               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+                       return -EINVAL;
+               svbi = &fmt->fmt.sliced;
+               memset(svbi, 0, sizeof(*svbi));
+
+               for (i = 0; i <= 23; i++) {
+                       svbi->service_lines[0][i]=tvp5150_get_vbi(c,
+                               vbi_ram_default,i);
+                       mask|=svbi->service_lines[0][i];
+               }
+               svbi->service_set=mask;
+               break;
+       }
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        case VIDIOC_INT_G_REGISTER:
        {
@@ -878,6 +948,7 @@ static int tvp5150_command(struct i2c_client *c,
        }
 #endif
 
+       case VIDIOC_LOG_STATUS:
        case DECODER_DUMP:
                dump_reg(c);
                break;
@@ -1097,7 +1168,7 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
 
        rv = i2c_attach_client(c);
 
-       core->norm = V4L2_STD_ALL;
+       core->norm = V4L2_STD_ALL;      /* Default is autodetect */
        core->input = 2;
        core->enable = 1;
        core->bright = 32768;
index cd45c1d..4240043 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder registers
+ *
+ * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
 #define TVP5150_VD_IN_SRC_SEL_1      0x00 /* Video input source selection #1 */
 #define TVP5150_ANAL_CHL_CTL         0x01 /* Analog channel controls */
 #define TVP5150_OP_MODE_CTL          0x02 /* Operation mode controls */
 #define TVP5150_STATUS_REG_4        0x8b /* Status register #4 */
 #define TVP5150_STATUS_REG_5        0x8c /* Status register #5 */
 /* Reserved    8Dh-8Fh */
-#define TVP5150_CC_DATA_REG1        0x90 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG2        0x91 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG3        0x92 /* Closed caption data registers */
-#define TVP5150_CC_DATA_REG4        0x93 /* Closed caption data registers */
-#define TVP5150_WSS_DATA_REG1       0X94 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG2       0X95 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG3       0X96 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG4       0X97 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG5       0X98 /* WSS data registers */
-#define TVP5150_WSS_DATA_REG6       0X99 /* WSS data registers */
-#define TVP5150_VPS_DATA_REG1       0x9a /* VPS data registers */
-#define TVP5150_VPS_DATA_REG2       0x9b /* VPS data registers */
-#define TVP5150_VPS_DATA_REG3       0x9c /* VPS data registers */
-#define TVP5150_VPS_DATA_REG4       0x9d /* VPS data registers */
-#define TVP5150_VPS_DATA_REG5       0x9e /* VPS data registers */
-#define TVP5150_VPS_DATA_REG6       0x9f /* VPS data registers */
-#define TVP5150_VPS_DATA_REG7       0xa0 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG8       0xa1 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG9       0xa2 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG10      0xa3 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG11      0xa4 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG12      0xa5 /* VPS data registers */
-#define TVP5150_VPS_DATA_REG13      0xa6 /* VPS data registers */
-#define TVP5150_VITC_DATA_REG1      0xa7 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG2      0xa8 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG3      0xa9 /* VITC data registers */
-#define TVP5150_VITC_DATA_REG4      0xaa /* VITC data registers */
-#define TVP5150_VITC_DATA_REG5      0xab /* VITC data registers */
-#define TVP5150_VITC_DATA_REG6      0xac /* VITC data registers */
-#define TVP5150_VITC_DATA_REG7      0xad /* VITC data registers */
-#define TVP5150_VITC_DATA_REG8      0xae /* VITC data registers */
-#define TVP5150_VITC_DATA_REG9      0xaf /* VITC data registers */
+ /* Closed caption data registers */
+#define TVP5150_CC_DATA_INI         0x90
+#define TVP5150_CC_DATA_END         0x93
+
+ /* WSS data registers */
+#define TVP5150_WSS_DATA_INI        0x94
+#define TVP5150_WSS_DATA_END        0x99
+
+/* VPS data registers */
+#define TVP5150_VPS_DATA_INI        0x9a
+#define TVP5150_VPS_DATA_END        0xa6
+
+/* VITC data registers */
+#define TVP5150_VITC_DATA_INI       0xa7
+#define TVP5150_VITC_DATA_END       0xaf
+
 #define TVP5150_VBI_FIFO_READ_DATA  0xb0 /* VBI FIFO read data */
-#define TVP5150_TELETEXT_FIL_1_1    0xb1 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_2    0xb2 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_3    0xb3 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_4    0xb4 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_1_5    0xb5 /* Teletext filter 1 */
-#define TVP5150_TELETEXT_FIL_2_1    0xb6 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_2    0xb7 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_3    0xb8 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_4    0xb9 /* Teletext filter 2 */
-#define TVP5150_TELETEXT_FIL_2_5    0xba /* Teletext filter 2 */
+
+/* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL1_INI  0xb1
+#define TVP5150_TELETEXT_FIL1_END  0xb5
+
+/* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL2_INI  0xb6
+#define TVP5150_TELETEXT_FIL2_END  0xba
+
 #define TVP5150_TELETEXT_FIL_ENA    0xbb /* Teletext filter enable */
 /* Reserved    BCh-BFh */
 #define TVP5150_INT_STATUS_REG_A    0xc0 /* Interrupt status register A */
 #define TVP5150_PIX_ALIGN_REG_HIGH  0xcc /* Pixel alignment register high byte */
 #define TVP5150_FIFO_OUT_CTRL       0xcd /* FIFO output control */
 /* Reserved    CEh */
-#define TVP5150_FULL_FIELD_ENA_1    0xcf /* Full field enable 1 */
-#define TVP5150_FULL_FIELD_ENA_2    0xd0 /* Full field enable 2 */
-#define TVP5150_LINE_MODE_REG_1     0xd1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_2     0xd2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_3     0xd3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_4     0xd4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_5     0xd5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_6     0xd6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_7     0xd7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_8     0xd8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_9     0xd9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_10    0xda /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_11    0xdb /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_12    0xdc /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_13    0xdd /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_14    0xde /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_15    0xdf /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_16    0xe0 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_17    0xe1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_18    0xe2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_19    0xe3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_20    0xe4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_21    0xe5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_22    0xe6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_23    0xe7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_24    0xe8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_25    0xe9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_27    0xea /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_28    0xeb /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_29    0xec /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_30    0xed /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_31    0xee /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_32    0xef /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_33    0xf0 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_34    0xf1 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_35    0xf2 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_36    0xf3 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_37    0xf4 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_38    0xf5 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_39    0xf6 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_40    0xf7 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_41    0xf8 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_42    0xf9 /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_43    0xfa /* Line mode registers */
-#define TVP5150_LINE_MODE_REG_44    0xfb /* Line mode registers */
+#define TVP5150_FULL_FIELD_ENA      0xcf /* Full field enable 1 */
+
+/* Line mode registers */
+#define TVP5150_LINE_MODE_INI       0xd0
+#define TVP5150_LINE_MODE_END       0xfb
+
 #define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */
 /* Reserved    FDh-FFh */
index cd2c447..95a6e47 100644 (file)
@@ -97,7 +97,7 @@ int v4l2_video_std_construct(struct v4l2_standard *vs,
        memset(vs, 0, sizeof(struct v4l2_standard));
        vs->index = index;
        vs->id    = id;
-       if (id & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) {
+       if (id & V4L2_STD_525_60) {
                vs->frameperiod.numerator = 1001;
                vs->frameperiod.denominator = 30000;
                vs->framelines = 525;
@@ -110,7 +110,6 @@ int v4l2_video_std_construct(struct v4l2_standard *vs,
        return 0;
 }
 
-
 /* ----------------------------------------------------------------- */
 /* priority handling                                                 */
 
@@ -171,7 +170,7 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local)
 
 
 /* ----------------------------------------------------------------- */
-/* some arrays for pretty-printing debug messages                    */
+/* some arrays for pretty-printing debug messages of enum types      */
 
 char *v4l2_field_names[] = {
        [V4L2_FIELD_ANY]        = "any",
@@ -192,6 +191,14 @@ char *v4l2_type_names[] = {
        [V4L2_BUF_TYPE_VBI_OUTPUT]    = "vbi-out",
 };
 
+static char *v4l2_memory_names[] = {
+       [V4L2_MEMORY_MMAP]    = "mmap",
+       [V4L2_MEMORY_USERPTR] = "userptr",
+       [V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+
 /* ------------------------------------------------------------------ */
 /* debug help functions                                               */
 
@@ -324,6 +331,15 @@ static const char *v4l2_int_ioctls[] = {
 };
 #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
 
+static void v4l_print_pix_fmt (char *s, struct v4l2_pix_format *fmt)
+{
+       printk ("%s: width=%d, height=%d, format=%d, field=%s, "
+               "bytesperline=%d sizeimage=%d, colorspace=%d\n", s,
+               fmt->width,fmt->height,fmt->pixelformat,
+               prt_names(fmt->field,v4l2_field_names),
+               fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+};
+
 /* Common ioctl debug function. This function can be used by
    external ioctl messages as well as internal V4L ioctl */
 void v4l_printk_ioctl(unsigned int cmd)
@@ -362,6 +378,541 @@ void v4l_printk_ioctl(unsigned int cmd)
        }
 }
 
+/* Common ioctl debug function. This function can be used by
+   external ioctl messages as well as internal V4L ioctl and its
+   arguments */
+void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
+{
+       printk(s);
+       printk(": ");
+       v4l_printk_ioctl(cmd);
+       switch (cmd) {
+       case VIDIOC_INT_G_CHIP_IDENT:
+       {
+               enum v4l2_chip_ident  *p=arg;
+               printk ("%s: chip ident=%d\n", s, *p);
+               break;
+       }
+       case VIDIOC_G_PRIORITY:
+       case VIDIOC_S_PRIORITY:
+       {
+               enum v4l2_priority *p=arg;
+               printk ("%s: priority=%d\n", s, *p);
+               break;
+       }
+       case VIDIOC_INT_S_TUNER_MODE:
+       {
+               enum v4l2_tuner_type *p=arg;
+               printk ("%s: tuner type=%d\n", s, *p);
+               break;
+       }
+       case DECODER_SET_VBI_BYPASS:
+       case DECODER_ENABLE_OUTPUT:
+       case DECODER_GET_STATUS:
+       case DECODER_SET_OUTPUT:
+       case DECODER_SET_INPUT:
+       case DECODER_SET_GPIO:
+       case DECODER_SET_NORM:
+       case VIDIOCCAPTURE:
+       case VIDIOCSYNC:
+       case VIDIOCSWRITEMODE:
+       case TUNER_SET_TYPE_ADDR:
+       case TUNER_SET_STANDBY:
+       case TDA9887_SET_CONFIG:
+       case AUDC_SET_INPUT:
+       case VIDIOC_OVERLAY_OLD:
+       case VIDIOC_STREAMOFF:
+       case VIDIOC_G_OUTPUT:
+       case VIDIOC_S_OUTPUT:
+       case VIDIOC_STREAMON:
+       case VIDIOC_G_INPUT:
+       case VIDIOC_OVERLAY:
+       case VIDIOC_S_INPUT:
+       {
+               int *p=arg;
+               printk ("%s: value=%d\n", s, *p);
+               break;
+       }
+       case MSP_SET_MATRIX:
+       {
+               struct msp_matrix *p=arg;
+               printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
+               break;
+       }
+       case VIDIOC_G_AUDIO:
+       case VIDIOC_S_AUDIO:
+       case VIDIOC_ENUMAUDIO:
+       case VIDIOC_G_AUDIO_OLD:
+       {
+               struct v4l2_audio *p=arg;
+
+               printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n",
+                       s,p->index, p->name,p->capability, p->mode);
+               break;
+       }
+       case VIDIOC_G_AUDOUT:
+       case VIDIOC_S_AUDOUT:
+       case VIDIOC_ENUMAUDOUT:
+       case VIDIOC_G_AUDOUT_OLD:
+       {
+               struct v4l2_audioout *p=arg;
+               printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
+                               p->index, p->name, p->capability,p->mode);
+               break;
+       }
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF:
+       case VIDIOC_QUERYBUF:
+       {
+               struct v4l2_buffer *p=arg;
+               struct v4l2_timecode *tc=&p->timecode;
+               printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
+                       "bytesused=%d, flags=0x%08d, "
+                       "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+                               s,
+                               (p->timestamp.tv_sec/3600),
+                               (int)(p->timestamp.tv_sec/60)%60,
+                               (int)(p->timestamp.tv_sec%60),
+                               p->timestamp.tv_usec,
+                               p->index,
+                               prt_names(p->type,v4l2_type_names),
+                               p->bytesused,p->flags,
+                               p->field,p->sequence,
+                               prt_names(p->memory,v4l2_memory_names),
+                               p->m.userptr);
+               printk ("%s: timecode= %02d:%02d:%02d type=%d, "
+                       "flags=0x%08d, frames=%d, userbits=0x%08x",
+                               s,tc->hours,tc->minutes,tc->seconds,
+                               tc->type, tc->flags, tc->frames, (__u32) tc->userbits);
+               break;
+       }
+       case VIDIOC_QUERYCAP:
+       {
+               struct v4l2_capability *p=arg;
+               printk ("%s: driver=%s, card=%s, bus=%s, version=%d, "
+                       "capabilities=%d\n", s,
+                               p->driver,p->card,p->bus_info,
+                               p->version,
+                               p->capabilities);
+               break;
+       }
+       case VIDIOC_G_CTRL:
+       case VIDIOC_S_CTRL:
+       case VIDIOC_S_CTRL_OLD:
+       {
+               struct v4l2_control *p=arg;
+               printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
+               break;
+       }
+       case VIDIOC_G_CROP:
+       case VIDIOC_S_CROP:
+       {
+               struct v4l2_crop *p=arg;
+               /*FIXME: Should also show rect structs */
+               printk ("%s: type=%d\n", s, p->type);
+               break;
+       }
+       case VIDIOC_CROPCAP:
+       case VIDIOC_CROPCAP_OLD:
+       {
+               struct v4l2_cropcap *p=arg;
+               /*FIXME: Should also show rect structs */
+               printk ("%s: type=%d\n", s, p->type);
+               break;
+       }
+       case VIDIOC_INT_DECODE_VBI_LINE:
+       {
+               struct v4l2_decode_vbi_line *p=arg;
+               printk ("%s: is_second_field=%d, ptr=0x%08lx, line=%d, "
+                       "type=%d\n", s,
+                               p->is_second_field,(unsigned long)p->p,p->line,p->type);
+               break;
+       }
+       case VIDIOC_ENUM_FMT:
+       {
+               struct v4l2_fmtdesc *p=arg;
+               printk ("%s: index=%d, type=%d, flags=%d, description=%s,"
+                       " pixelformat=%d\n", s,
+                               p->index, p->type, p->flags,p->description,
+                               p->pixelformat);
+
+               break;
+       }
+       case VIDIOC_G_FMT:
+       case VIDIOC_S_FMT:
+       case VIDIOC_TRY_FMT:
+       {
+               struct v4l2_format *p=arg;
+               printk ("%s: type=%s\n", s,
+                               prt_names(p->type,v4l2_type_names));
+               switch (p->type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       v4l_print_pix_fmt (s, &p->fmt.pix);
+                       break;
+               default:
+                       break;
+               }
+       }
+       case VIDIOC_G_FBUF:
+       case VIDIOC_S_FBUF:
+       {
+               struct v4l2_framebuffer *p=arg;
+               printk ("%s: capability=%d, flags=%d, base=0x%08lx\n", s,
+                               p->capability,p->flags, (unsigned long)p->base);
+               v4l_print_pix_fmt (s, &p->fmt);
+               break;
+       }
+       case VIDIOC_G_FREQUENCY:
+       case VIDIOC_S_FREQUENCY:
+       {
+               struct v4l2_frequency *p=arg;
+               printk ("%s: tuner=%d, type=%d, frequency=%d\n", s,
+                               p->tuner,p->type,p->frequency);
+               break;
+       }
+       case VIDIOC_ENUMINPUT:
+       {
+               struct v4l2_input *p=arg;
+               printk ("%s: index=%d, name=%s, type=%d, audioset=%d, "
+                       "tuner=%d, std=%lld, status=%d\n", s,
+                               p->index,p->name,p->type,p->audioset,
+                               p->tuner,p->std,
+                               p->status);
+               break;
+       }
+       case VIDIOC_G_JPEGCOMP:
+       case VIDIOC_S_JPEGCOMP:
+       {
+               struct v4l2_jpegcompression *p=arg;
+               printk ("%s: quality=%d, APPn=%d, APP_len=%d, COM_len=%d,"
+                       " jpeg_markers=%d\n", s,
+                               p->quality,p->APPn,p->APP_len,
+                               p->COM_len,p->jpeg_markers);
+               break;
+       }
+       case VIDIOC_G_MODULATOR:
+       case VIDIOC_S_MODULATOR:
+       {
+               struct v4l2_modulator *p=arg;
+               printk ("%s: index=%d, name=%s, capability=%d, rangelow=%d,"
+                       " rangehigh=%d, txsubchans=%d\n", s,
+                               p->index, p->name,p->capability,p->rangelow,
+                               p->rangehigh,p->txsubchans);
+               break;
+       }
+       case VIDIOC_G_MPEGCOMP:
+       case VIDIOC_S_MPEGCOMP:
+       {
+               struct v4l2_mpeg_compression *p=arg;
+               /*FIXME: Several fields not shown */
+               printk ("%s: ts_pid_pmt=%d, ts_pid_audio=%d, ts_pid_video=%d, "
+                       "ts_pid_pcr=%d, ps_size=%d, au_sample_rate=%d, "
+                       "au_pesid=%c, vi_frame_rate=%d, vi_frames_per_gop=%d, "
+                       "vi_bframes_count=%d, vi_pesid=%c\n", s,
+                               p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
+                               p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
+                               p->au_pesid, p->vi_frame_rate,
+                               p->vi_frames_per_gop, p->vi_bframes_count,
+                               p->vi_pesid);
+               break;
+       }
+       case VIDIOC_ENUMOUTPUT:
+       {
+               struct v4l2_output *p=arg;
+               printk ("%s: index=%d, name=%s,type=%d, audioset=%d, "
+                       "modulator=%d, std=%lld\n",
+                               s,p->index,p->name,p->type,p->audioset,
+                               p->modulator,p->std);
+               break;
+       }
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *p=arg;
+               printk ("%s: id=%d, type=%d, name=%s, min/max=%d/%d,"
+                       " step=%d, default=%d, flags=0x%08x\n", s,
+                               p->id,p->type,p->name,p->minimum,p->maximum,
+                               p->step,p->default_value,p->flags);
+               break;
+       }
+       case VIDIOC_QUERYMENU:
+       {
+               struct v4l2_querymenu *p=arg;
+               printk ("%s: id=%d, index=%d, name=%s\n", s,
+                               p->id,p->index,p->name);
+               break;
+       }
+       case VIDIOC_INT_G_REGISTER:
+       case VIDIOC_INT_S_REGISTER:
+       {
+               struct v4l2_register *p=arg;
+               printk ("%s: i2c_id=%d, reg=%lu, val=%d\n", s,
+                               p->i2c_id,p->reg,p->val);
+
+               break;
+       }
+       case VIDIOC_REQBUFS:
+       {
+               struct v4l2_requestbuffers *p=arg;
+               printk ("%s: count=%d, type=%s, memory=%s\n", s,
+                               p->count,
+                               prt_names(p->type,v4l2_type_names),
+                               prt_names(p->memory,v4l2_memory_names));
+               break;
+       }
+       case VIDIOC_INT_S_AUDIO_ROUTING:
+       case VIDIOC_INT_S_VIDEO_ROUTING:
+       case VIDIOC_INT_G_AUDIO_ROUTING:
+       case VIDIOC_INT_G_VIDEO_ROUTING:
+       {
+               struct v4l2_routing  *p=arg;
+               printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
+               break;
+       }
+       case VIDIOC_G_SLICED_VBI_CAP:
+       {
+               struct v4l2_sliced_vbi_cap *p=arg;
+               printk ("%s: service_set=%d\n", s,
+                               p->service_set);
+               break;
+       }
+       case VIDIOC_INT_S_VBI_DATA:
+       case VIDIOC_INT_G_VBI_DATA:
+       {
+               struct v4l2_sliced_vbi_data  *p=arg;
+               printk ("%s: id=%d, field=%d, line=%d\n", s,
+                               p->id, p->field, p->line);
+               break;
+       }
+       case VIDIOC_ENUMSTD:
+       {
+               struct v4l2_standard *p=arg;
+               printk ("%s: index=%d, id=%lld, name=%s, fps=%d/%d, framelines=%d\n", s,
+                               p->index, p->id, p->name,
+                               p->frameperiod.numerator,
+                               p->frameperiod.denominator,
+                               p->framelines);
+
+               break;
+       }
+       case VIDIOC_G_PARM:
+       case VIDIOC_S_PARM:
+       case VIDIOC_S_PARM_OLD:
+       {
+               struct v4l2_streamparm *p=arg;
+               printk ("%s: type=%d\n", s, p->type);
+
+               break;
+       }
+       case VIDIOC_G_TUNER:
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *p=arg;
+               printk ("%s: index=%d, name=%s, type=%d, capability=%d, "
+                       "rangelow=%d, rangehigh=%d, signal=%d, afc=%d, "
+                       "rxsubchans=%d, audmode=%d\n", s,
+                               p->index, p->name, p->type,
+                               p->capability, p->rangelow,p->rangehigh,
+                               p->rxsubchans, p->audmode, p->signal,
+                               p->afc);
+               break;
+       }
+       case VIDIOCGVBIFMT:
+       case VIDIOCSVBIFMT:
+       {
+               struct vbi_format *p=arg;
+               printk ("%s: sampling_rate=%d, samples_per_line=%d, "
+                       "sample_format=%d, start=%d/%d, count=%d/%d, flags=%d\n", s,
+                               p->sampling_rate,p->samples_per_line,
+                               p->sample_format,p->start[0],p->start[1],
+                               p->count[0],p->count[1],p->flags);
+               break;
+       }
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+       {
+               struct video_audio *p=arg;
+               printk ("%s: audio=%d, volume=%d, bass=%d, treble=%d, "
+                       "flags=%d, name=%s, mode=%d, balance=%d, step=%d\n",
+                               s,p->audio,p->volume,p->bass, p->treble,
+                               p->flags,p->name,p->mode,p->balance,p->step);
+               break;
+       }
+       case VIDIOCGFBUF:
+       case VIDIOCSFBUF:
+       {
+               struct video_buffer *p=arg;
+               printk ("%s: base=%08lx, height=%d, width=%d, depth=%d, "
+                       "bytesperline=%d\n", s,
+                               (unsigned long) p->base, p->height, p->width,
+                               p->depth,p->bytesperline);
+               break;
+       }
+       case VIDIOCGCAP:
+       {
+               struct video_capability *p=arg;
+               printk ("%s: name=%s, type=%d, channels=%d, audios=%d, "
+                       "maxwidth=%d, maxheight=%d, minwidth=%d, minheight=%d\n",
+                               s,p->name,p->type,p->channels,p->audios,
+                               p->maxwidth,p->maxheight,p->minwidth,
+                               p->minheight);
+
+               break;
+       }
+       case VIDIOCGCAPTURE:
+       case VIDIOCSCAPTURE:
+       {
+               struct video_capture *p=arg;
+               printk ("%s: x=%d, y=%d, width=%d, height=%d, decimation=%d,"
+                       " flags=%d\n", s,
+                               p->x, p->y,p->width, p->height,
+                               p->decimation,p->flags);
+               break;
+       }
+       case VIDIOCGCHAN:
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *p=arg;
+               printk ("%s: channel=%d, name=%s, tuners=%d, flags=%d, "
+                       "type=%d, norm=%d\n", s,
+                               p->channel,p->name,p->tuners,
+                               p->flags,p->type,p->norm);
+
+               break;
+       }
+       case VIDIOCSMICROCODE:
+       {
+               struct video_code *p=arg;
+               printk ("%s: loadwhat=%s, datasize=%d\n", s,
+                               p->loadwhat,p->datasize);
+               break;
+       }
+       case DECODER_GET_CAPABILITIES:
+       {
+               struct video_decoder_capability *p=arg;
+               printk ("%s: flags=%d, inputs=%d, outputs=%d\n", s,
+                               p->flags,p->inputs,p->outputs);
+               break;
+       }
+       case DECODER_INIT:
+       {
+               struct video_decoder_init *p=arg;
+               printk ("%s: len=%c\n", s, p->len);
+               break;
+       }
+       case VIDIOCGPLAYINFO:
+       {
+               struct video_info *p=arg;
+               printk ("%s: frame_count=%d, h_size=%d, v_size=%d, "
+                       "smpte_timecode=%d, picture_type=%d, "
+                       "temporal_reference=%d, user_data=%s\n", s,
+                               p->frame_count, p->h_size,
+                               p->v_size, p->smpte_timecode,
+                               p->picture_type, p->temporal_reference,
+                               p->user_data);
+               break;
+       }
+       case VIDIOCKEY:
+       {
+               struct video_key *p=arg;
+               printk ("%s: key=%s, flags=%d\n", s,
+                               p->key, p->flags);
+               break;
+       }
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *p=arg;
+               printk ("%s: size=%d, frames=%d, offsets=0x%08lx\n", s,
+                               p->size,
+                               p->frames,
+                               (unsigned long)p->offsets);
+               break;
+       }
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap *p=arg;
+               printk ("%s: frame=%d, height=%d, width=%d, format=%d\n", s,
+                               p->frame,
+                               p->height, p->width,
+                               p->format);
+               break;
+       }
+       case VIDIOCGPICT:
+       case VIDIOCSPICT:
+       case DECODER_SET_PICTURE:
+       {
+               struct video_picture *p=arg;
+
+               printk ("%s: brightness=%d, hue=%d, colour=%d, contrast=%d,"
+                       " whiteness=%d, depth=%d, palette=%d\n", s,
+                               p->brightness, p->hue, p->colour,
+                               p->contrast, p->whiteness, p->depth,
+                               p->palette);
+               break;
+       }
+       case VIDIOCSPLAYMODE:
+       {
+               struct video_play_mode *p=arg;
+               printk ("%s: mode=%d, p1=%d, p2=%d\n", s,
+                               p->mode,p->p1,p->p2);
+               break;
+       }
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+       {
+               struct video_tuner *p=arg;
+               printk ("%s: tuner=%d, name=%s, rangelow=%ld, rangehigh=%ld, "
+                       "flags=%d, mode=%d, signal=%d\n", s,
+                               p->tuner, p->name,p->rangelow, p->rangehigh,
+                               p->flags,p->mode, p->signal);
+               break;
+       }
+       case VIDIOCGUNIT:
+       {
+               struct video_unit *p=arg;
+               printk ("%s: video=%d, vbi=%d, radio=%d, audio=%d, "
+                       "teletext=%d\n", s,
+                               p->video,p->vbi,p->radio,p->audio,p->teletext);
+               break;
+       }
+       case VIDIOCGWIN:
+       case VIDIOCSWIN:
+       {
+               struct video_window *p=arg;
+               printk ("%s: x=%d, y=%d, width=%d, height=%d, chromakey=%d,"
+                       " flags=%d, clipcount=%d\n", s,
+                               p->x, p->y,p->width, p->height,
+                               p->chromakey,p->flags,
+                               p->clipcount);
+               break;
+       }
+       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+       case VIDIOC_INT_I2S_CLOCK_FREQ:
+       case VIDIOC_INT_S_STANDBY:
+       {
+               u32 *p=arg;
+
+               printk ("%s: value=%d\n", s, *p);
+               break;
+       }
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       {
+               unsigned long *p=arg;
+               printk ("%s: value=%lu\n", s, *p);
+               break;
+       }
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       {
+               v4l2_std_id *p=arg;
+
+               printk ("%s: value=%llu\n", s, *p);
+               break;
+       }
+       }
+}
+
 /* ----------------------------------------------------------------- */
 
 EXPORT_SYMBOL(v4l2_video_std_construct);
@@ -376,6 +927,7 @@ EXPORT_SYMBOL(v4l2_prio_check);
 EXPORT_SYMBOL(v4l2_field_names);
 EXPORT_SYMBOL(v4l2_type_names);
 EXPORT_SYMBOL(v4l_printk_ioctl);
+EXPORT_SYMBOL(v4l_printk_ioctl_arg);
 
 /*
  * Local variables:
index 0a4004a..caf3e7e 100644 (file)
@@ -96,7 +96,7 @@ static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed)
        if (!demux->dmx.frontend)
                return -EINVAL;
 
-       down(&dvb->lock);
+       mutex_lock(&dvb->lock);
        dvb->nfeeds++;
        rc = dvb->nfeeds;
 
@@ -110,7 +110,7 @@ static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed)
        }
 
 out:
-       up(&dvb->lock);
+       mutex_unlock(&dvb->lock);
        return rc;
 }
 
@@ -120,14 +120,14 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
        struct videobuf_dvb *dvb = demux->priv;
        int err = 0;
 
-       down(&dvb->lock);
+       mutex_lock(&dvb->lock);
        dvb->nfeeds--;
        if (0 == dvb->nfeeds  &&  NULL != dvb->thread) {
                // FIXME: cx8802_cancel_buffers(dev);
                err = kthread_stop(dvb->thread);
                dvb->thread = NULL;
        }
-       up(&dvb->lock);
+       mutex_unlock(&dvb->lock);
        return err;
 }
 
@@ -139,7 +139,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb,
 {
        int result;
 
-       init_MUTEX(&dvb->lock);
+       mutex_init(&dvb->lock);
 
        /* register adapter */
        result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
index 9ef4775..87e9375 100644 (file)
@@ -59,8 +59,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
                pg = vmalloc_to_page(virt);
                if (NULL == pg)
                        goto err;
-               if (PageHighMem(pg))
-                       BUG();
+               BUG_ON(PageHighMem(pg));
                sglist[i].page   = pg;
                sglist[i].length = PAGE_SIZE;
        }
@@ -385,7 +384,7 @@ void videobuf_queue_init(struct videobuf_queue* q,
        q->ops     = ops;
        q->priv_data = priv;
 
-       init_MUTEX(&q->lock);
+       mutex_init(&q->lock);
        INIT_LIST_HEAD(&q->stream);
 }
 
@@ -428,7 +427,7 @@ videobuf_queue_is_busy(struct videobuf_queue *q)
 void
 videobuf_queue_cancel(struct videobuf_queue *q)
 {
-       unsigned long flags;
+       unsigned long flags=0;
        int i;
 
        /* remove queued buffers from list */
@@ -549,7 +548,7 @@ videobuf_reqbufs(struct videobuf_queue *q,
        if (!list_empty(&q->stream))
                return -EBUSY;
 
-       down(&q->lock);
+       mutex_lock(&q->lock);
        count = req->count;
        if (count > VIDEO_MAX_FRAME)
                count = VIDEO_MAX_FRAME;
@@ -566,7 +565,7 @@ videobuf_reqbufs(struct videobuf_queue *q,
        req->count = count;
 
  done:
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return retval;
 }
 
@@ -589,10 +588,10 @@ videobuf_qbuf(struct videobuf_queue *q,
 {
        struct videobuf_buffer *buf;
        enum v4l2_field field;
-       unsigned long flags;
+       unsigned long flags=0;
        int retval;
 
-       down(&q->lock);
+       mutex_lock(&q->lock);
        retval = -EBUSY;
        if (q->reading)
                goto done;
@@ -652,7 +651,7 @@ videobuf_qbuf(struct videobuf_queue *q,
        retval = 0;
 
  done:
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return retval;
 }
 
@@ -663,7 +662,7 @@ videobuf_dqbuf(struct videobuf_queue *q,
        struct videobuf_buffer *buf;
        int retval;
 
-       down(&q->lock);
+       mutex_lock(&q->lock);
        retval = -EBUSY;
        if (q->reading)
                goto done;
@@ -693,7 +692,7 @@ videobuf_dqbuf(struct videobuf_queue *q,
        videobuf_status(b,buf,q->type);
 
  done:
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return retval;
 }
 
@@ -701,10 +700,10 @@ int videobuf_streamon(struct videobuf_queue *q)
 {
        struct videobuf_buffer *buf;
        struct list_head *list;
-       unsigned long flags;
+       unsigned long flags=0;
        int retval;
 
-       down(&q->lock);
+       mutex_lock(&q->lock);
        retval = -EBUSY;
        if (q->reading)
                goto done;
@@ -721,7 +720,7 @@ int videobuf_streamon(struct videobuf_queue *q)
        spin_unlock_irqrestore(q->irqlock,flags);
 
  done:
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return retval;
 }
 
@@ -729,7 +728,7 @@ int videobuf_streamoff(struct videobuf_queue *q)
 {
        int retval = -EINVAL;
 
-       down(&q->lock);
+       mutex_lock(&q->lock);
        if (!q->streaming)
                goto done;
        videobuf_queue_cancel(q);
@@ -737,7 +736,7 @@ int videobuf_streamoff(struct videobuf_queue *q)
        retval = 0;
 
  done:
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return retval;
 }
 
@@ -746,7 +745,7 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
                       size_t count, loff_t *ppos)
 {
        enum v4l2_field field;
-       unsigned long flags;
+       unsigned long flags=0;
        int retval;
 
        /* setup stuff */
@@ -788,11 +787,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
                          int nonblocking)
 {
        enum v4l2_field field;
-       unsigned long flags;
+       unsigned long flags=0;
        unsigned size, nbufs, bytes;
        int retval;
 
-       down(&q->lock);
+       mutex_lock(&q->lock);
 
        nbufs = 1; size = 0;
        q->ops->buf_setup(q,&nbufs,&size);
@@ -860,14 +859,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
  done:
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return retval;
 }
 
 int videobuf_read_start(struct videobuf_queue *q)
 {
        enum v4l2_field field;
-       unsigned long flags;
+       unsigned long flags=0;
        int count = 0, size = 0;
        int err, i;
 
@@ -919,10 +918,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
 {
        unsigned int *fc, bytes;
        int err, retval;
-       unsigned long flags;
+       unsigned long flags=0;
 
        dprintk(2,"%s\n",__FUNCTION__);
-       down(&q->lock);
+       mutex_lock(&q->lock);
        retval = -EBUSY;
        if (q->streaming)
                goto done;
@@ -996,7 +995,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
        }
 
  done:
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return retval;
 }
 
@@ -1007,7 +1006,7 @@ unsigned int videobuf_poll_stream(struct file *file,
        struct videobuf_buffer *buf = NULL;
        unsigned int rc = 0;
 
-       down(&q->lock);
+       mutex_lock(&q->lock);
        if (q->streaming) {
                if (!list_empty(&q->stream))
                        buf = list_entry(q->stream.next,
@@ -1035,7 +1034,7 @@ unsigned int videobuf_poll_stream(struct file *file,
                    buf->state == STATE_ERROR)
                        rc = POLLIN|POLLRDNORM;
        }
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return rc;
 }
 
@@ -1064,7 +1063,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
        map->count--;
        if (0 == map->count) {
                dprintk(1,"munmap %p q=%p\n",map,q);
-               down(&q->lock);
+               mutex_lock(&q->lock);
                for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                        if (NULL == q->bufs[i])
                                continue;
@@ -1076,7 +1075,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
                        q->bufs[i]->baddr = 0;
                        q->ops->buf_release(q,q->bufs[i]);
                }
-               up(&q->lock);
+               mutex_unlock(&q->lock);
                kfree(map);
        }
        return;
@@ -1170,7 +1169,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
        unsigned int first,last,size,i;
        int retval;
 
-       down(&q->lock);
+       mutex_lock(&q->lock);
        retval = -EINVAL;
        if (!(vma->vm_flags & VM_WRITE)) {
                dprintk(1,"mmap app bug: PROT_WRITE please\n");
@@ -1238,7 +1237,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
        retval = 0;
 
  done:
-       up(&q->lock);
+       mutex_unlock(&q->lock);
        return retval;
 }
 
index 078880e..75e3d41 100644 (file)
@@ -224,13 +224,13 @@ int video_exclusive_open(struct inode *inode, struct file *file)
        struct  video_device *vfl = video_devdata(file);
        int retval = 0;
 
-       down(&vfl->lock);
+       mutex_lock(&vfl->lock);
        if (vfl->users) {
                retval = -EBUSY;
        } else {
                vfl->users++;
        }
-       up(&vfl->lock);
+       mutex_unlock(&vfl->lock);
        return retval;
 }
 
@@ -279,23 +279,23 @@ int video_register_device(struct video_device *vfd, int type, int nr)
        switch(type)
        {
                case VFL_TYPE_GRABBER:
-                       base=0;
-                       end=64;
+                       base=MINOR_VFL_TYPE_GRABBER_MIN;
+                       end=MINOR_VFL_TYPE_GRABBER_MAX+1;
                        name_base = "video";
                        break;
                case VFL_TYPE_VTX:
-                       base=192;
-                       end=224;
+                       base=MINOR_VFL_TYPE_VTX_MIN;
+                       end=MINOR_VFL_TYPE_VTX_MAX+1;
                        name_base = "vtx";
                        break;
                case VFL_TYPE_VBI:
-                       base=224;
-                       end=256;
+                       base=MINOR_VFL_TYPE_VBI_MIN;
+                       end=MINOR_VFL_TYPE_VBI_MAX+1;
                        name_base = "vbi";
                        break;
                case VFL_TYPE_RADIO:
-                       base=64;
-                       end=128;
+                       base=MINOR_VFL_TYPE_RADIO_MIN;
+                       end=MINOR_VFL_TYPE_RADIO_MAX+1;
                        name_base = "radio";
                        break;
                default:
@@ -328,7 +328,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
        sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base);
        devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor),
                        S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name);
-       init_MUTEX(&vfd->lock);
+       mutex_init(&vfd->lock);
 
        /* sysfs class */
        memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
index c8fd823..0229819 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <linux/video_decoder.h>
+#include <linux/mutex.h>
 
 #include <asm/paccess.h>
 #include <asm/io.h>
@@ -245,7 +246,7 @@ struct vino_framebuffer_queue {
        struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX];
 
        spinlock_t queue_lock;
-       struct semaphore queue_sem;
+       struct mutex queue_mutex;
        wait_queue_head_t frame_wait_queue;
 };
 
@@ -283,7 +284,7 @@ struct vino_channel_settings {
        /* the driver is currently processing the queue */
        int capturing;
 
-       struct semaphore sem;
+       struct mutex mutex;
        spinlock_t capture_lock;
 
        unsigned int users;
@@ -1131,11 +1132,11 @@ static void vino_queue_free(struct vino_framebuffer_queue *q)
        if (q->type != VINO_MEMORY_MMAP)
                return;
 
-       down(&q->queue_sem);
+       mutex_lock(&q->queue_mutex);
 
        vino_queue_free_with_count(q, q->length);
 
-       up(&q->queue_sem);
+       mutex_unlock(&q->queue_mutex);
 }
 
 static int vino_queue_init(struct vino_framebuffer_queue *q,
@@ -1159,7 +1160,7 @@ static int vino_queue_init(struct vino_framebuffer_queue *q,
        if (*length < 1)
                return -EINVAL;
 
-       down(&q->queue_sem);
+       mutex_lock(&q->queue_mutex);
 
        if (*length > VINO_FRAMEBUFFER_COUNT_MAX)
                *length = VINO_FRAMEBUFFER_COUNT_MAX;
@@ -1211,7 +1212,7 @@ static int vino_queue_init(struct vino_framebuffer_queue *q,
                q->magic = VINO_QUEUE_MAGIC;
        }
 
-       up(&q->queue_sem);
+       mutex_unlock(&q->queue_mutex);
 
        return ret;
 }
@@ -4045,7 +4046,7 @@ static int vino_open(struct inode *inode, struct file *file)
        dprintk("open(): channel = %c\n",
               (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
 
-       down(&vcs->sem);
+       mutex_lock(&vcs->mutex);
 
        if (vcs->users) {
                dprintk("open(): driver busy\n");
@@ -4062,7 +4063,7 @@ static int vino_open(struct inode *inode, struct file *file)
        vcs->users++;
 
  out:
-       up(&vcs->sem);
+       mutex_unlock(&vcs->mutex);
 
        dprintk("open(): %s!\n", ret ? "failed" : "complete");
 
@@ -4075,7 +4076,7 @@ static int vino_close(struct inode *inode, struct file *file)
        struct vino_channel_settings *vcs = video_get_drvdata(dev);
        dprintk("close():\n");
 
-       down(&vcs->sem);
+       mutex_lock(&vcs->mutex);
 
        vcs->users--;
 
@@ -4087,7 +4088,7 @@ static int vino_close(struct inode *inode, struct file *file)
                vino_queue_free(&vcs->fb_queue);
        }
 
-       up(&vcs->sem);
+       mutex_unlock(&vcs->mutex);
 
        return 0;
 }
@@ -4130,7 +4131,7 @@ static int vino_mmap(struct file *file, struct vm_area_struct *vma)
 
        // TODO: reject mmap if already mapped
 
-       if (down_interruptible(&vcs->sem))
+       if (mutex_lock_interruptible(&vcs->mutex))
                return -EINTR;
 
        if (vcs->reading) {
@@ -4214,7 +4215,7 @@ found:
        vma->vm_ops = &vino_vm_ops;
 
 out:
-       up(&vcs->sem);
+       mutex_unlock(&vcs->mutex);
 
        return ret;
 }
@@ -4374,12 +4375,12 @@ static int vino_ioctl(struct inode *inode, struct file *file,
        struct vino_channel_settings *vcs = video_get_drvdata(dev);
        int ret;
 
-       if (down_interruptible(&vcs->sem))
+       if (mutex_lock_interruptible(&vcs->mutex))
                return -EINTR;
 
        ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl);
 
-       up(&vcs->sem);
+       mutex_unlock(&vcs->mutex);
 
        return ret;
 }
@@ -4564,10 +4565,10 @@ static int vino_init_channel_settings(struct vino_channel_settings *vcs,
 
        vcs->capturing = 0;
 
-       init_MUTEX(&vcs->sem);
+       mutex_init(&vcs->mutex);
        spin_lock_init(&vcs->capture_lock);
 
-       init_MUTEX(&vcs->fb_queue.queue_sem);
+       mutex_init(&vcs->fb_queue.queue_mutex);
        spin_lock_init(&vcs->fb_queue.queue_lock);
        init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
 
index 285d7d0..c32fad1 100644 (file)
@@ -438,7 +438,7 @@ static int pxamci_probe(struct platform_device *pdev)
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (!r || irq == NO_IRQ)
+       if (!r || irq < 0)
                return -ENXIO;
 
        r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
index e58d4c5..f5ee064 100644 (file)
@@ -1605,7 +1605,7 @@ static void rtl8139_thread (void *_data)
        if (tp->watchdog_fired) {
                tp->watchdog_fired = 0;
                rtl8139_tx_timeout_task(_data);
-       } else if (rtnl_shlock_nowait() == 0) {
+       } else if (rtnl_trylock()) {
                rtl8139_thread_iter (dev, tp, tp->mmio_addr);
                rtnl_unlock ();
        } else {
index 53e3afc..09d5c3f 100644 (file)
@@ -696,7 +696,9 @@ static int __init am79c961_probe(struct platform_device *pdev)
        dev->base_addr = res->start;
        dev->irq = platform_get_irq(pdev, 0);
 
-       ret = -ENODEV;
+       ret = -ENODEV;
+       if (dev->irq < 0)
+               goto nodev;
        if (!request_region(dev->base_addr, 0x18, dev->name))
                goto nodev;
 
index b787b65..7d21370 100644 (file)
@@ -14,8 +14,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.4.31"
-#define DRV_MODULE_RELDATE     "January 19, 2006"
+#define DRV_MODULE_VERSION     "1.4.38"
+#define DRV_MODULE_RELDATE     "February 10, 2006"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -360,6 +360,8 @@ bnx2_netif_start(struct bnx2 *bp)
 static void
 bnx2_free_mem(struct bnx2 *bp)
 {
+       int i;
+
        if (bp->stats_blk) {
                pci_free_consistent(bp->pdev, sizeof(struct statistics_block),
                                    bp->stats_blk, bp->stats_blk_mapping);
@@ -378,19 +380,23 @@ bnx2_free_mem(struct bnx2 *bp)
        }
        kfree(bp->tx_buf_ring);
        bp->tx_buf_ring = NULL;
-       if (bp->rx_desc_ring) {
-               pci_free_consistent(bp->pdev,
-                                   sizeof(struct rx_bd) * RX_DESC_CNT,
-                                   bp->rx_desc_ring, bp->rx_desc_mapping);
-               bp->rx_desc_ring = NULL;
-       }
-       kfree(bp->rx_buf_ring);
+       for (i = 0; i < bp->rx_max_ring; i++) {
+               if (bp->rx_desc_ring[i])
+                       pci_free_consistent(bp->pdev,
+                                           sizeof(struct rx_bd) * RX_DESC_CNT,
+                                           bp->rx_desc_ring[i],
+                                           bp->rx_desc_mapping[i]);
+               bp->rx_desc_ring[i] = NULL;
+       }
+       vfree(bp->rx_buf_ring);
        bp->rx_buf_ring = NULL;
 }
 
 static int
 bnx2_alloc_mem(struct bnx2 *bp)
 {
+       int i;
+
        bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
                                     GFP_KERNEL);
        if (bp->tx_buf_ring == NULL)
@@ -404,18 +410,23 @@ bnx2_alloc_mem(struct bnx2 *bp)
        if (bp->tx_desc_ring == NULL)
                goto alloc_mem_err;
 
-       bp->rx_buf_ring = kmalloc(sizeof(struct sw_bd) * RX_DESC_CNT,
-                                    GFP_KERNEL);
+       bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *
+                                 bp->rx_max_ring);
        if (bp->rx_buf_ring == NULL)
                goto alloc_mem_err;
 
-       memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT);
-       bp->rx_desc_ring = pci_alloc_consistent(bp->pdev,
-                                               sizeof(struct rx_bd) *
-                                               RX_DESC_CNT,
-                                               &bp->rx_desc_mapping);
-       if (bp->rx_desc_ring == NULL)
-               goto alloc_mem_err;
+       memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT *
+                                  bp->rx_max_ring);
+
+       for (i = 0; i < bp->rx_max_ring; i++) {
+               bp->rx_desc_ring[i] =
+                       pci_alloc_consistent(bp->pdev,
+                                            sizeof(struct rx_bd) * RX_DESC_CNT,
+                                            &bp->rx_desc_mapping[i]);
+               if (bp->rx_desc_ring[i] == NULL)
+                       goto alloc_mem_err;
+
+       }
 
        bp->status_blk = pci_alloc_consistent(bp->pdev,
                                              sizeof(struct status_block),
@@ -1520,7 +1531,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
        struct sk_buff *skb;
        struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
        dma_addr_t mapping;
-       struct rx_bd *rxbd = &bp->rx_desc_ring[index];
+       struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
        unsigned long align;
 
        skb = dev_alloc_skb(bp->rx_buf_size);
@@ -1656,23 +1667,30 @@ static inline void
 bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
        u16 cons, u16 prod)
 {
-       struct sw_bd *cons_rx_buf = &bp->rx_buf_ring[cons];
-       struct sw_bd *prod_rx_buf = &bp->rx_buf_ring[prod];
-       struct rx_bd *cons_bd = &bp->rx_desc_ring[cons];
-       struct rx_bd *prod_bd = &bp->rx_desc_ring[prod];
+       struct sw_bd *cons_rx_buf, *prod_rx_buf;
+       struct rx_bd *cons_bd, *prod_bd;
+
+       cons_rx_buf = &bp->rx_buf_ring[cons];
+       prod_rx_buf = &bp->rx_buf_ring[prod];
 
        pci_dma_sync_single_for_device(bp->pdev,
                pci_unmap_addr(cons_rx_buf, mapping),
                bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
-       prod_rx_buf->skb = cons_rx_buf->skb;
-       pci_unmap_addr_set(prod_rx_buf, mapping,
-                       pci_unmap_addr(cons_rx_buf, mapping));
+       bp->rx_prod_bseq += bp->rx_buf_use_size;
 
-       memcpy(prod_bd, cons_bd, 8);
+       prod_rx_buf->skb = skb;
 
-       bp->rx_prod_bseq += bp->rx_buf_use_size;
+       if (cons == prod)
+               return;
 
+       pci_unmap_addr_set(prod_rx_buf, mapping,
+                       pci_unmap_addr(cons_rx_buf, mapping));
+
+       cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
+       prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
+       prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
+       prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
 }
 
 static int
@@ -1699,14 +1717,19 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
                u32 status;
                struct sw_bd *rx_buf;
                struct sk_buff *skb;
+               dma_addr_t dma_addr;
 
                sw_ring_cons = RX_RING_IDX(sw_cons);
                sw_ring_prod = RX_RING_IDX(sw_prod);
 
                rx_buf = &bp->rx_buf_ring[sw_ring_cons];
                skb = rx_buf->skb;
-               pci_dma_sync_single_for_cpu(bp->pdev,
-                       pci_unmap_addr(rx_buf, mapping),
+
+               rx_buf->skb = NULL;
+
+               dma_addr = pci_unmap_addr(rx_buf, mapping);
+
+               pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
                        bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
                rx_hdr = (struct l2_fhdr *) skb->data;
@@ -1747,8 +1770,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
                        skb = new_skb;
                }
                else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) {
-                       pci_unmap_single(bp->pdev,
-                               pci_unmap_addr(rx_buf, mapping),
+                       pci_unmap_single(bp->pdev, dma_addr,
                                bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
 
                        skb_reserve(skb, bp->rx_offset);
@@ -1794,8 +1816,6 @@ reuse_rx:
                rx_pkt++;
 
 next_rx:
-               rx_buf->skb = NULL;
-
                sw_cons = NEXT_RX_BD(sw_cons);
                sw_prod = NEXT_RX_BD(sw_prod);
 
@@ -3340,27 +3360,35 @@ bnx2_init_rx_ring(struct bnx2 *bp)
        bp->hw_rx_cons = 0;
        bp->rx_prod_bseq = 0;
                
-       rxbd = &bp->rx_desc_ring[0];
-       for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
-               rxbd->rx_bd_len = bp->rx_buf_use_size;
-               rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
-       }
+       for (i = 0; i < bp->rx_max_ring; i++) {
+               int j;
 
-       rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping >> 32;
-       rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping & 0xffffffff;
+               rxbd = &bp->rx_desc_ring[i][0];
+               for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
+                       rxbd->rx_bd_len = bp->rx_buf_use_size;
+                       rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
+               }
+               if (i == (bp->rx_max_ring - 1))
+                       j = 0;
+               else
+                       j = i + 1;
+               rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32;
+               rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] &
+                                      0xffffffff;
+       }
 
        val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
        val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
        val |= 0x02 << 8;
        CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
 
-       val = (u64) bp->rx_desc_mapping >> 32;
+       val = (u64) bp->rx_desc_mapping[0] >> 32;
        CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
 
-       val = (u64) bp->rx_desc_mapping & 0xffffffff;
+       val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
        CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
 
-       for ( ;ring_prod < bp->rx_ring_size; ) {
+       for (i = 0; i < bp->rx_ring_size; i++) {
                if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
                        break;
                }
@@ -3375,6 +3403,29 @@ bnx2_init_rx_ring(struct bnx2 *bp)
 }
 
 static void
+bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
+{
+       u32 num_rings, max;
+
+       bp->rx_ring_size = size;
+       num_rings = 1;
+       while (size > MAX_RX_DESC_CNT) {
+               size -= MAX_RX_DESC_CNT;
+               num_rings++;
+       }
+       /* round to next power of 2 */
+       max = MAX_RX_RINGS;
+       while ((max & num_rings) == 0)
+               max >>= 1;
+
+       if (num_rings != max)
+               max <<= 1;
+
+       bp->rx_max_ring = max;
+       bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
+}
+
+static void
 bnx2_free_tx_skbs(struct bnx2 *bp)
 {
        int i;
@@ -3419,7 +3470,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
        if (bp->rx_buf_ring == NULL)
                return;
 
-       for (i = 0; i < RX_DESC_CNT; i++) {
+       for (i = 0; i < bp->rx_max_ring_idx; i++) {
                struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
                struct sk_buff *skb = rx_buf->skb;
 
@@ -3506,74 +3557,9 @@ bnx2_test_registers(struct bnx2 *bp)
                { 0x0c00, 0, 0x00000000, 0x00000001 },
                { 0x0c04, 0, 0x00000000, 0x03ff0001 },
                { 0x0c08, 0, 0x0f0ff073, 0x00000000 },
-               { 0x0c0c, 0, 0x00ffffff, 0x00000000 },
-               { 0x0c30, 0, 0x00000000, 0xffffffff },
-               { 0x0c34, 0, 0x00000000, 0xffffffff },
-               { 0x0c38, 0, 0x00000000, 0xffffffff },
-               { 0x0c3c, 0, 0x00000000, 0xffffffff },
-               { 0x0c40, 0, 0x00000000, 0xffffffff },
-               { 0x0c44, 0, 0x00000000, 0xffffffff },
-               { 0x0c48, 0, 0x00000000, 0x0007ffff },
-               { 0x0c4c, 0, 0x00000000, 0xffffffff },
-               { 0x0c50, 0, 0x00000000, 0xffffffff },
-               { 0x0c54, 0, 0x00000000, 0xffffffff },
-               { 0x0c58, 0, 0x00000000, 0xffffffff },
-               { 0x0c5c, 0, 0x00000000, 0xffffffff },
-               { 0x0c60, 0, 0x00000000, 0xffffffff },
-               { 0x0c64, 0, 0x00000000, 0xffffffff },
-               { 0x0c68, 0, 0x00000000, 0xffffffff },
-               { 0x0c6c, 0, 0x00000000, 0xffffffff },
-               { 0x0c70, 0, 0x00000000, 0xffffffff },
-               { 0x0c74, 0, 0x00000000, 0xffffffff },
-               { 0x0c78, 0, 0x00000000, 0xffffffff },
-               { 0x0c7c, 0, 0x00000000, 0xffffffff },
-               { 0x0c80, 0, 0x00000000, 0xffffffff },
-               { 0x0c84, 0, 0x00000000, 0xffffffff },
-               { 0x0c88, 0, 0x00000000, 0xffffffff },
-               { 0x0c8c, 0, 0x00000000, 0xffffffff },
-               { 0x0c90, 0, 0x00000000, 0xffffffff },
-               { 0x0c94, 0, 0x00000000, 0xffffffff },
-               { 0x0c98, 0, 0x00000000, 0xffffffff },
-               { 0x0c9c, 0, 0x00000000, 0xffffffff },
-               { 0x0ca0, 0, 0x00000000, 0xffffffff },
-               { 0x0ca4, 0, 0x00000000, 0xffffffff },
-               { 0x0ca8, 0, 0x00000000, 0x0007ffff },
-               { 0x0cac, 0, 0x00000000, 0xffffffff },
-               { 0x0cb0, 0, 0x00000000, 0xffffffff },
-               { 0x0cb4, 0, 0x00000000, 0xffffffff },
-               { 0x0cb8, 0, 0x00000000, 0xffffffff },
-               { 0x0cbc, 0, 0x00000000, 0xffffffff },
-               { 0x0cc0, 0, 0x00000000, 0xffffffff },
-               { 0x0cc4, 0, 0x00000000, 0xffffffff },
-               { 0x0cc8, 0, 0x00000000, 0xffffffff },
-               { 0x0ccc, 0, 0x00000000, 0xffffffff },
-               { 0x0cd0, 0, 0x00000000, 0xffffffff },
-               { 0x0cd4, 0, 0x00000000, 0xffffffff },
-               { 0x0cd8, 0, 0x00000000, 0xffffffff },
-               { 0x0cdc, 0, 0x00000000, 0xffffffff },
-               { 0x0ce0, 0, 0x00000000, 0xffffffff },
-               { 0x0ce4, 0, 0x00000000, 0xffffffff },
-               { 0x0ce8, 0, 0x00000000, 0xffffffff },
-               { 0x0cec, 0, 0x00000000, 0xffffffff },
-               { 0x0cf0, 0, 0x00000000, 0xffffffff },
-               { 0x0cf4, 0, 0x00000000, 0xffffffff },
-               { 0x0cf8, 0, 0x00000000, 0xffffffff },
-               { 0x0cfc, 0, 0x00000000, 0xffffffff },
-               { 0x0d00, 0, 0x00000000, 0xffffffff },
-               { 0x0d04, 0, 0x00000000, 0xffffffff },
 
                { 0x1000, 0, 0x00000000, 0x00000001 },
                { 0x1004, 0, 0x00000000, 0x000f0001 },
-               { 0x1044, 0, 0x00000000, 0xffc003ff },
-               { 0x1080, 0, 0x00000000, 0x0001ffff },
-               { 0x1084, 0, 0x00000000, 0xffffffff },
-               { 0x1088, 0, 0x00000000, 0xffffffff },
-               { 0x108c, 0, 0x00000000, 0xffffffff },
-               { 0x1090, 0, 0x00000000, 0xffffffff },
-               { 0x1094, 0, 0x00000000, 0xffffffff },
-               { 0x1098, 0, 0x00000000, 0xffffffff },
-               { 0x109c, 0, 0x00000000, 0xffffffff },
-               { 0x10a0, 0, 0x00000000, 0xffffffff },
 
                { 0x1408, 0, 0x01c00800, 0x00000000 },
                { 0x149c, 0, 0x8000ffff, 0x00000000 },
@@ -3585,111 +3571,9 @@ bnx2_test_registers(struct bnx2 *bp)
                { 0x14c4, 0, 0x00003fff, 0x00000000 },
                { 0x14cc, 0, 0x00000000, 0x00000001 },
                { 0x14d0, 0, 0xffffffff, 0x00000000 },
-               { 0x1500, 0, 0x00000000, 0xffffffff },
-               { 0x1504, 0, 0x00000000, 0xffffffff },
-               { 0x1508, 0, 0x00000000, 0xffffffff },
-               { 0x150c, 0, 0x00000000, 0xffffffff },
-               { 0x1510, 0, 0x00000000, 0xffffffff },
-               { 0x1514, 0, 0x00000000, 0xffffffff },
-               { 0x1518, 0, 0x00000000, 0xffffffff },
-               { 0x151c, 0, 0x00000000, 0xffffffff },
-               { 0x1520, 0, 0x00000000, 0xffffffff },
-               { 0x1524, 0, 0x00000000, 0xffffffff },
-               { 0x1528, 0, 0x00000000, 0xffffffff },
-               { 0x152c, 0, 0x00000000, 0xffffffff },
-               { 0x1530, 0, 0x00000000, 0xffffffff },
-               { 0x1534, 0, 0x00000000, 0xffffffff },
-               { 0x1538, 0, 0x00000000, 0xffffffff },
-               { 0x153c, 0, 0x00000000, 0xffffffff },
-               { 0x1540, 0, 0x00000000, 0xffffffff },
-               { 0x1544, 0, 0x00000000, 0xffffffff },
-               { 0x1548, 0, 0x00000000, 0xffffffff },
-               { 0x154c, 0, 0x00000000, 0xffffffff },
-               { 0x1550, 0, 0x00000000, 0xffffffff },
-               { 0x1554, 0, 0x00000000, 0xffffffff },
-               { 0x1558, 0, 0x00000000, 0xffffffff },
-               { 0x1600, 0, 0x00000000, 0xffffffff },
-               { 0x1604, 0, 0x00000000, 0xffffffff },
-               { 0x1608, 0, 0x00000000, 0xffffffff },
-               { 0x160c, 0, 0x00000000, 0xffffffff },
-               { 0x1610, 0, 0x00000000, 0xffffffff },
-               { 0x1614, 0, 0x00000000, 0xffffffff },
-               { 0x1618, 0, 0x00000000, 0xffffffff },
-               { 0x161c, 0, 0x00000000, 0xffffffff },
-               { 0x1620, 0, 0x00000000, 0xffffffff },
-               { 0x1624, 0, 0x00000000, 0xffffffff },
-               { 0x1628, 0, 0x00000000, 0xffffffff },
-               { 0x162c, 0, 0x00000000, 0xffffffff },
-               { 0x1630, 0, 0x00000000, 0xffffffff },
-               { 0x1634, 0, 0x00000000, 0xffffffff },
-               { 0x1638, 0, 0x00000000, 0xffffffff },
-               { 0x163c, 0, 0x00000000, 0xffffffff },
-               { 0x1640, 0, 0x00000000, 0xffffffff },
-               { 0x1644, 0, 0x00000000, 0xffffffff },
-               { 0x1648, 0, 0x00000000, 0xffffffff },
-               { 0x164c, 0, 0x00000000, 0xffffffff },
-               { 0x1650, 0, 0x00000000, 0xffffffff },
-               { 0x1654, 0, 0x00000000, 0xffffffff },
 
                { 0x1800, 0, 0x00000000, 0x00000001 },
                { 0x1804, 0, 0x00000000, 0x00000003 },
-               { 0x1840, 0, 0x00000000, 0xffffffff },
-               { 0x1844, 0, 0x00000000, 0xffffffff },
-               { 0x1848, 0, 0x00000000, 0xffffffff },
-               { 0x184c, 0, 0x00000000, 0xffffffff },
-               { 0x1850, 0, 0x00000000, 0xffffffff },
-               { 0x1900, 0, 0x7ffbffff, 0x00000000 },
-               { 0x1904, 0, 0xffffffff, 0x00000000 },
-               { 0x190c, 0, 0xffffffff, 0x00000000 },
-               { 0x1914, 0, 0xffffffff, 0x00000000 },
-               { 0x191c, 0, 0xffffffff, 0x00000000 },
-               { 0x1924, 0, 0xffffffff, 0x00000000 },
-               { 0x192c, 0, 0xffffffff, 0x00000000 },
-               { 0x1934, 0, 0xffffffff, 0x00000000 },
-               { 0x193c, 0, 0xffffffff, 0x00000000 },
-               { 0x1944, 0, 0xffffffff, 0x00000000 },
-               { 0x194c, 0, 0xffffffff, 0x00000000 },
-               { 0x1954, 0, 0xffffffff, 0x00000000 },
-               { 0x195c, 0, 0xffffffff, 0x00000000 },
-               { 0x1964, 0, 0xffffffff, 0x00000000 },
-               { 0x196c, 0, 0xffffffff, 0x00000000 },
-               { 0x1974, 0, 0xffffffff, 0x00000000 },
-               { 0x197c, 0, 0xffffffff, 0x00000000 },
-               { 0x1980, 0, 0x0700ffff, 0x00000000 },
-
-               { 0x1c00, 0, 0x00000000, 0x00000001 },
-               { 0x1c04, 0, 0x00000000, 0x00000003 },
-               { 0x1c08, 0, 0x0000000f, 0x00000000 },
-               { 0x1c40, 0, 0x00000000, 0xffffffff },
-               { 0x1c44, 0, 0x00000000, 0xffffffff },
-               { 0x1c48, 0, 0x00000000, 0xffffffff },
-               { 0x1c4c, 0, 0x00000000, 0xffffffff },
-               { 0x1c50, 0, 0x00000000, 0xffffffff },
-               { 0x1d00, 0, 0x7ffbffff, 0x00000000 },
-               { 0x1d04, 0, 0xffffffff, 0x00000000 },
-               { 0x1d0c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d14, 0, 0xffffffff, 0x00000000 },
-               { 0x1d1c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d24, 0, 0xffffffff, 0x00000000 },
-               { 0x1d2c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d34, 0, 0xffffffff, 0x00000000 },
-               { 0x1d3c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d44, 0, 0xffffffff, 0x00000000 },
-               { 0x1d4c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d54, 0, 0xffffffff, 0x00000000 },
-               { 0x1d5c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d64, 0, 0xffffffff, 0x00000000 },
-               { 0x1d6c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d74, 0, 0xffffffff, 0x00000000 },
-               { 0x1d7c, 0, 0xffffffff, 0x00000000 },
-               { 0x1d80, 0, 0x0700ffff, 0x00000000 },
-
-               { 0x2004, 0, 0x00000000, 0x0337000f },
-               { 0x2008, 0, 0xffffffff, 0x00000000 },
-               { 0x200c, 0, 0xffffffff, 0x00000000 },
-               { 0x2010, 0, 0xffffffff, 0x00000000 },
-               { 0x2014, 0, 0x801fff80, 0x00000000 },
-               { 0x2018, 0, 0x000003ff, 0x00000000 },
 
                { 0x2800, 0, 0x00000000, 0x00000001 },
                { 0x2804, 0, 0x00000000, 0x00003f01 },
@@ -3707,16 +3591,6 @@ bnx2_test_registers(struct bnx2 *bp)
                { 0x2c00, 0, 0x00000000, 0x00000011 },
                { 0x2c04, 0, 0x00000000, 0x00030007 },
 
-               { 0x3000, 0, 0x00000000, 0x00000001 },
-               { 0x3004, 0, 0x00000000, 0x007007ff },
-               { 0x3008, 0, 0x00000003, 0x00000000 },
-               { 0x300c, 0, 0xffffffff, 0x00000000 },
-               { 0x3010, 0, 0xffffffff, 0x00000000 },
-               { 0x3014, 0, 0xffffffff, 0x00000000 },
-               { 0x3034, 0, 0xffffffff, 0x00000000 },
-               { 0x3038, 0, 0xffffffff, 0x00000000 },
-               { 0x3050, 0, 0x00000001, 0x00000000 },
-
                { 0x3c00, 0, 0x00000000, 0x00000001 },
                { 0x3c04, 0, 0x00000000, 0x00070000 },
                { 0x3c08, 0, 0x00007f71, 0x07f00000 },
@@ -3726,88 +3600,11 @@ bnx2_test_registers(struct bnx2 *bp)
                { 0x3c18, 0, 0x00000000, 0xffffffff },
                { 0x3c1c, 0, 0xfffff000, 0x00000000 },
                { 0x3c20, 0, 0xffffff00, 0x00000000 },
-               { 0x3c24, 0, 0xffffffff, 0x00000000 },
-               { 0x3c28, 0, 0xffffffff, 0x00000000 },
-               { 0x3c2c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c30, 0, 0xffffffff, 0x00000000 },
-               { 0x3c34, 0, 0xffffffff, 0x00000000 },
-               { 0x3c38, 0, 0xffffffff, 0x00000000 },
-               { 0x3c3c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c40, 0, 0xffffffff, 0x00000000 },
-               { 0x3c44, 0, 0xffffffff, 0x00000000 },
-               { 0x3c48, 0, 0xffffffff, 0x00000000 },
-               { 0x3c4c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c50, 0, 0xffffffff, 0x00000000 },
-               { 0x3c54, 0, 0xffffffff, 0x00000000 },
-               { 0x3c58, 0, 0xffffffff, 0x00000000 },
-               { 0x3c5c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c60, 0, 0xffffffff, 0x00000000 },
-               { 0x3c64, 0, 0xffffffff, 0x00000000 },
-               { 0x3c68, 0, 0xffffffff, 0x00000000 },
-               { 0x3c6c, 0, 0xffffffff, 0x00000000 },
-               { 0x3c70, 0, 0xffffffff, 0x00000000 },
-               { 0x3c74, 0, 0x0000003f, 0x00000000 },
-               { 0x3c78, 0, 0x00000000, 0x00000000 },
-               { 0x3c7c, 0, 0x00000000, 0x00000000 },
-               { 0x3c80, 0, 0x3fffffff, 0x00000000 },
-               { 0x3c84, 0, 0x0000003f, 0x00000000 },
-               { 0x3c88, 0, 0x00000000, 0xffffffff },
-               { 0x3c8c, 0, 0x00000000, 0xffffffff },
-
-               { 0x4000, 0, 0x00000000, 0x00000001 },
-               { 0x4004, 0, 0x00000000, 0x00030000 },
-               { 0x4008, 0, 0x00000ff0, 0x00000000 },
-               { 0x400c, 0, 0xffffffff, 0x00000000 },
-               { 0x4088, 0, 0x00000000, 0x00070303 },
-
-               { 0x4400, 0, 0x00000000, 0x00000001 },
-               { 0x4404, 0, 0x00000000, 0x00003f01 },
-               { 0x4408, 0, 0x7fff00ff, 0x00000000 },
-               { 0x440c, 0, 0xffffffff, 0x00000000 },
-               { 0x4410, 0, 0xffff,     0x0000 },
-               { 0x4414, 0, 0xffff,     0x0000 },
-               { 0x4418, 0, 0xffff,     0x0000 },
-               { 0x441c, 0, 0xffff,     0x0000 },
-               { 0x4428, 0, 0xffffffff, 0x00000000 },
-               { 0x442c, 0, 0xffffffff, 0x00000000 },
-               { 0x4430, 0, 0xffffffff, 0x00000000 },
-               { 0x4434, 0, 0xffffffff, 0x00000000 },
-               { 0x4438, 0, 0xffffffff, 0x00000000 },
-               { 0x443c, 0, 0xffffffff, 0x00000000 },
-               { 0x4440, 0, 0xffffffff, 0x00000000 },
-               { 0x4444, 0, 0xffffffff, 0x00000000 },
-
-               { 0x4c00, 0, 0x00000000, 0x00000001 },
-               { 0x4c04, 0, 0x00000000, 0x0000003f },
-               { 0x4c08, 0, 0xffffffff, 0x00000000 },
-               { 0x4c0c, 0, 0x0007fc00, 0x00000000 },
-               { 0x4c10, 0, 0x80003fe0, 0x00000000 },
-               { 0x4c14, 0, 0xffffffff, 0x00000000 },
-               { 0x4c44, 0, 0x00000000, 0x9fff9fff },
-               { 0x4c48, 0, 0x00000000, 0xb3009fff },
-               { 0x4c4c, 0, 0x00000000, 0x77f33b30 },
-               { 0x4c50, 0, 0x00000000, 0xffffffff },
 
                { 0x5004, 0, 0x00000000, 0x0000007f },
                { 0x5008, 0, 0x0f0007ff, 0x00000000 },
                { 0x500c, 0, 0xf800f800, 0x07ff07ff },
 
-               { 0x5400, 0, 0x00000008, 0x00000001 },
-               { 0x5404, 0, 0x00000000, 0x0000003f },
-               { 0x5408, 0, 0x0000001f, 0x00000000 },
-               { 0x540c, 0, 0xffffffff, 0x00000000 },
-               { 0x5410, 0, 0xffffffff, 0x00000000 },
-               { 0x5414, 0, 0x0000ffff, 0x00000000 },
-               { 0x5418, 0, 0x0000ffff, 0x00000000 },
-               { 0x541c, 0, 0x0000ffff, 0x00000000 },
-               { 0x5420, 0, 0x0000ffff, 0x00000000 },
-               { 0x5428, 0, 0x000000ff, 0x00000000 },
-               { 0x542c, 0, 0xff00ffff, 0x00000000 },
-               { 0x5430, 0, 0x001fff80, 0x00000000 },
-               { 0x5438, 0, 0xffffffff, 0x00000000 },
-               { 0x543c, 0, 0xffffffff, 0x00000000 },
-               { 0x5440, 0, 0xf800f800, 0x07ff07ff },
-
                { 0x5c00, 0, 0x00000000, 0x00000001 },
                { 0x5c04, 0, 0x00000000, 0x0003000f },
                { 0x5c08, 0, 0x00000003, 0x00000000 },
@@ -4794,6 +4591,64 @@ bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        info->fw_version[5] = 0;
 }
 
+#define BNX2_REGDUMP_LEN               (32 * 1024)
+
+static int
+bnx2_get_regs_len(struct net_device *dev)
+{
+       return BNX2_REGDUMP_LEN;
+}
+
+static void
+bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
+{
+       u32 *p = _p, i, offset;
+       u8 *orig_p = _p;
+       struct bnx2 *bp = netdev_priv(dev);
+       u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
+                                0x0800, 0x0880, 0x0c00, 0x0c10,
+                                0x0c30, 0x0d08, 0x1000, 0x101c,
+                                0x1040, 0x1048, 0x1080, 0x10a4,
+                                0x1400, 0x1490, 0x1498, 0x14f0,
+                                0x1500, 0x155c, 0x1580, 0x15dc,
+                                0x1600, 0x1658, 0x1680, 0x16d8,
+                                0x1800, 0x1820, 0x1840, 0x1854,
+                                0x1880, 0x1894, 0x1900, 0x1984,
+                                0x1c00, 0x1c0c, 0x1c40, 0x1c54,
+                                0x1c80, 0x1c94, 0x1d00, 0x1d84,
+                                0x2000, 0x2030, 0x23c0, 0x2400,
+                                0x2800, 0x2820, 0x2830, 0x2850,
+                                0x2b40, 0x2c10, 0x2fc0, 0x3058,
+                                0x3c00, 0x3c94, 0x4000, 0x4010,
+                                0x4080, 0x4090, 0x43c0, 0x4458,
+                                0x4c00, 0x4c18, 0x4c40, 0x4c54,
+                                0x4fc0, 0x5010, 0x53c0, 0x5444,
+                                0x5c00, 0x5c18, 0x5c80, 0x5c90,
+                                0x5fc0, 0x6000, 0x6400, 0x6428,
+                                0x6800, 0x6848, 0x684c, 0x6860,
+                                0x6888, 0x6910, 0x8000 };
+
+       regs->version = 0;
+
+       memset(p, 0, BNX2_REGDUMP_LEN);
+
+       if (!netif_running(bp->dev))
+               return;
+
+       i = 0;
+       offset = reg_boundaries[0];
+       p += offset;
+       while (offset < BNX2_REGDUMP_LEN) {
+               *p++ = REG_RD(bp, offset);
+               offset += 4;
+               if (offset == reg_boundaries[i + 1]) {
+                       offset = reg_boundaries[i + 2];
+                       p = (u32 *) (orig_p + offset);
+                       i += 2;
+               }
+       }
+}
+
 static void
 bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
@@ -4979,7 +4834,7 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
-       ering->rx_max_pending = MAX_RX_DESC_CNT;
+       ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
        ering->rx_mini_max_pending = 0;
        ering->rx_jumbo_max_pending = 0;
 
@@ -4996,17 +4851,28 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
-       if ((ering->rx_pending > MAX_RX_DESC_CNT) ||
+       if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
                (ering->tx_pending > MAX_TX_DESC_CNT) ||
                (ering->tx_pending <= MAX_SKB_FRAGS)) {
 
                return -EINVAL;
        }
-       bp->rx_ring_size = ering->rx_pending;
+       if (netif_running(bp->dev)) {
+               bnx2_netif_stop(bp);
+               bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
+               bnx2_free_skbs(bp);
+               bnx2_free_mem(bp);
+       }
+
+       bnx2_set_rx_ring_size(bp, ering->rx_pending);
        bp->tx_ring_size = ering->tx_pending;
 
        if (netif_running(bp->dev)) {
-               bnx2_netif_stop(bp);
+               int rc;
+
+               rc = bnx2_alloc_mem(bp);
+               if (rc)
+                       return rc;
                bnx2_init_nic(bp);
                bnx2_netif_start(bp);
        }
@@ -5360,6 +5226,8 @@ static struct ethtool_ops bnx2_ethtool_ops = {
        .get_settings           = bnx2_get_settings,
        .set_settings           = bnx2_set_settings,
        .get_drvinfo            = bnx2_get_drvinfo,
+       .get_regs_len           = bnx2_get_regs_len,
+       .get_regs               = bnx2_get_regs,
        .get_wol                = bnx2_get_wol,
        .set_wol                = bnx2_set_wol,
        .nway_reset             = bnx2_nway_reset,
@@ -5678,7 +5546,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->mac_addr[5] = (u8) reg;
 
        bp->tx_ring_size = MAX_TX_DESC_CNT;
-       bp->rx_ring_size = 100;
+       bnx2_set_rx_ring_size(bp, 100);
 
        bp->rx_csum = 1;
 
@@ -5897,6 +5765,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
        if (!netif_running(dev))
                return 0;
 
+       flush_scheduled_work();
        bnx2_netif_stop(bp);
        netif_device_detach(dev);
        del_timer_sync(&bp->timer);
index 9f691cb..fd4b7f2 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -3792,8 +3793,10 @@ struct l2_fhdr {
 #define TX_DESC_CNT  (BCM_PAGE_SIZE / sizeof(struct tx_bd))
 #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
 
+#define MAX_RX_RINGS   4
 #define RX_DESC_CNT  (BCM_PAGE_SIZE / sizeof(struct rx_bd))
 #define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
+#define MAX_TOTAL_RX_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_RINGS)
 
 #define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) ==                        \
                (MAX_TX_DESC_CNT - 1)) ?                                \
@@ -3805,8 +3808,10 @@ struct l2_fhdr {
                (MAX_RX_DESC_CNT - 1)) ?                                \
        (x) + 2 : (x) + 1
 
-#define RX_RING_IDX(x) ((x) & MAX_RX_DESC_CNT)
+#define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx)
 
+#define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> 8)
+#define RX_IDX(x) ((x) & MAX_RX_DESC_CNT)
 
 /* Context size. */
 #define CTX_SHIFT                   7
@@ -3903,6 +3908,15 @@ struct bnx2 {
        struct status_block     *status_blk;
        u32                     last_status_idx;
 
+       u32                     flags;
+#define PCIX_FLAG                      1
+#define PCI_32BIT_FLAG                 2
+#define ONE_TDMA_FLAG                  4       /* no longer used */
+#define NO_WOL_FLAG                    8
+#define USING_DAC_FLAG                 0x10
+#define USING_MSI_FLAG                 0x20
+#define ASF_ENABLE_FLAG                        0x40
+
        struct tx_bd            *tx_desc_ring;
        struct sw_bd            *tx_buf_ring;
        u32                     tx_prod_bseq;
@@ -3920,19 +3934,22 @@ struct bnx2 {
        u32                     rx_offset;
        u32                     rx_buf_use_size;        /* useable size */
        u32                     rx_buf_size;            /* with alignment */
-       struct rx_bd            *rx_desc_ring;
-       struct sw_bd            *rx_buf_ring;
+       u32                     rx_max_ring_idx;
+
        u32                     rx_prod_bseq;
        u16                     rx_prod;
        u16                     rx_cons;
 
        u32                     rx_csum;
 
+       struct sw_bd            *rx_buf_ring;
+       struct rx_bd            *rx_desc_ring[MAX_RX_RINGS];
+
        /* Only used to synchronize netif_stop_queue/wake_queue when tx */
        /* ring is full */
        spinlock_t              tx_lock;
 
-       /* End of fileds used in the performance code paths. */
+       /* End of fields used in the performance code paths. */
 
        char                    *name;
 
@@ -3945,15 +3962,6 @@ struct bnx2 {
        /* Used to synchronize phy accesses. */
        spinlock_t              phy_lock;
 
-       u32                     flags;
-#define PCIX_FLAG                      1
-#define PCI_32BIT_FLAG                 2
-#define ONE_TDMA_FLAG                  4       /* no longer used */
-#define NO_WOL_FLAG                    8
-#define USING_DAC_FLAG                 0x10
-#define USING_MSI_FLAG                 0x20
-#define ASF_ENABLE_FLAG                        0x40
-
        u32                     phy_flags;
 #define PHY_SERDES_FLAG                        1
 #define PHY_CRC_FIX_FLAG               2
@@ -4004,8 +4012,9 @@ struct bnx2 {
        dma_addr_t              tx_desc_mapping;
 
 
+       int                     rx_max_ring;
        int                     rx_ring_size;
-       dma_addr_t              rx_desc_mapping;
+       dma_addr_t              rx_desc_mapping[MAX_RX_RINGS];
 
        u16                     tx_quick_cons_trip;
        u16                     tx_quick_cons_trip_int;
index 6e295fc..8f1573e 100644 (file)
@@ -91,6 +91,7 @@
 #include <linux/mii.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <linux/mutex.h>
 
 #include <net/checksum.h>
 
@@ -3892,7 +3893,7 @@ static void cas_reset(struct cas *cp, int blkflag)
        spin_unlock(&cp->stat_lock[N_TX_RINGS]);
 }
 
-/* Shut down the chip, must be called with pm_sem held.  */
+/* Shut down the chip, must be called with pm_mutex held.  */
 static void cas_shutdown(struct cas *cp)
 {
        unsigned long flags;
@@ -4311,11 +4312,11 @@ static int cas_open(struct net_device *dev)
        int hw_was_up, err;
        unsigned long flags;
 
-       down(&cp->pm_sem);
+       mutex_lock(&cp->pm_mutex);
 
        hw_was_up = cp->hw_running;
 
-       /* The power-management semaphore protects the hw_running
+       /* The power-management mutex protects the hw_running
         * etc. state so it is safe to do this bit without cp->lock
         */
        if (!cp->hw_running) {
@@ -4364,7 +4365,7 @@ static int cas_open(struct net_device *dev)
        cas_unlock_all_restore(cp, flags);
 
        netif_start_queue(dev);
-       up(&cp->pm_sem);
+       mutex_unlock(&cp->pm_mutex);
        return 0;
 
 err_spare:
@@ -4372,7 +4373,7 @@ err_spare:
        cas_free_rxds(cp);
 err_tx_tiny:
        cas_tx_tiny_free(cp);
-       up(&cp->pm_sem);
+       mutex_unlock(&cp->pm_mutex);
        return err;
 }
 
@@ -4382,7 +4383,7 @@ static int cas_close(struct net_device *dev)
        struct cas *cp = netdev_priv(dev);
 
        /* Make sure we don't get distracted by suspend/resume */
-       down(&cp->pm_sem);
+       mutex_lock(&cp->pm_mutex);
 
        netif_stop_queue(dev);
 
@@ -4399,7 +4400,7 @@ static int cas_close(struct net_device *dev)
        cas_spare_free(cp);
        cas_free_rxds(cp);
        cas_tx_tiny_free(cp);
-       up(&cp->pm_sem);
+       mutex_unlock(&cp->pm_mutex);
        return 0;
 }
 
@@ -4834,10 +4835,10 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        unsigned long flags;
        int rc = -EOPNOTSUPP;
        
-       /* Hold the PM semaphore while doing ioctl's or we may collide
+       /* Hold the PM mutex while doing ioctl's or we may collide
         * with open/close and power management and oops.
         */
-       down(&cp->pm_sem);
+       mutex_lock(&cp->pm_mutex);
        switch (cmd) {
        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
                data->phy_id = cp->phy_addr;
@@ -4867,7 +4868,7 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                break;
        };
 
-       up(&cp->pm_sem);
+       mutex_unlock(&cp->pm_mutex);
        return rc;
 }
 
@@ -4994,7 +4995,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
                spin_lock_init(&cp->tx_lock[i]);
        }
        spin_lock_init(&cp->stat_lock[N_TX_RINGS]);
-       init_MUTEX(&cp->pm_sem);
+       mutex_init(&cp->pm_mutex);
 
        init_timer(&cp->link_timer);
        cp->link_timer.function = cas_link_timer;
@@ -5116,10 +5117,10 @@ err_out_free_consistent:
                            cp->init_block, cp->block_dvma);
 
 err_out_iounmap:
-       down(&cp->pm_sem);
+       mutex_lock(&cp->pm_mutex);
        if (cp->hw_running)
                cas_shutdown(cp);
-       up(&cp->pm_sem);
+       mutex_unlock(&cp->pm_mutex);
 
        iounmap(cp->regs);
 
@@ -5152,11 +5153,11 @@ static void __devexit cas_remove_one(struct pci_dev *pdev)
        cp = netdev_priv(dev);
        unregister_netdev(dev);
 
-       down(&cp->pm_sem);
+       mutex_lock(&cp->pm_mutex);
        flush_scheduled_work();
        if (cp->hw_running)
                cas_shutdown(cp);
-       up(&cp->pm_sem);
+       mutex_unlock(&cp->pm_mutex);
 
 #if 1
        if (cp->orig_cacheline_size) {
@@ -5183,10 +5184,7 @@ static int cas_suspend(struct pci_dev *pdev, pm_message_t state)
        struct cas *cp = netdev_priv(dev);
        unsigned long flags;
 
-       /* We hold the PM semaphore during entire driver
-        * sleep time
-        */
-       down(&cp->pm_sem);
+       mutex_lock(&cp->pm_mutex);
        
        /* If the driver is opened, we stop the DMA */
        if (cp->opened) {
@@ -5206,6 +5204,7 @@ static int cas_suspend(struct pci_dev *pdev, pm_message_t state)
 
        if (cp->hw_running)
                cas_shutdown(cp);
+       mutex_unlock(&cp->pm_mutex);
 
        return 0;
 }
@@ -5217,6 +5216,7 @@ static int cas_resume(struct pci_dev *pdev)
 
        printk(KERN_INFO "%s: resuming\n", dev->name);
 
+       mutex_lock(&cp->pm_mutex);
        cas_hard_reset(cp);
        if (cp->opened) {
                unsigned long flags;
@@ -5229,7 +5229,7 @@ static int cas_resume(struct pci_dev *pdev)
 
                netif_device_attach(dev);
        }
-       up(&cp->pm_sem);
+       mutex_unlock(&cp->pm_mutex);
        return 0;
 }
 #endif /* CONFIG_PM */
index 88063ef..ab55c7e 100644 (file)
@@ -4284,7 +4284,7 @@ struct cas {
         * (ie. not power managed) */
        int hw_running;
        int opened;
-       struct semaphore pm_sem; /* open/close/suspend/resume */
+       struct mutex pm_mutex; /* open/close/suspend/resume */
 
        struct cas_init_block *init_block;
        struct cas_tx_desc *init_txds[MAX_TX_RINGS];
index f39de16..49cd096 100644 (file)
@@ -920,7 +920,7 @@ e1000_remove(struct pci_dev *pdev)
        unregister_netdev(netdev);
 #ifdef CONFIG_E1000_NAPI
        for (i = 0; i < adapter->num_rx_queues; i++)
-               __dev_put(&adapter->polling_netdev[i]);
+               dev_put(&adapter->polling_netdev[i]);
 #endif
 
        if (!e1000_check_phy_reset_block(&adapter->hw))
index e67b1d0..95e2bb8 100644 (file)
@@ -118,6 +118,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
 
        /* Fill out IRQ field */
        fep->interrupt = platform_get_irq(pdev, 0);
+       if (fep->interrupt < 0)
+               return -EINVAL;
 
        /* Attach the memory for the FCC Parameter RAM */
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
index 2e8f444..3dad69d 100644 (file)
@@ -144,6 +144,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
        
        /* Fill out IRQ field */
        fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
+       if (fep->interrupt < 0)
+               return -EINVAL;
        
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
        fep->fec.fecp =(void*)r->start;
index a3897fd..a772b28 100644 (file)
@@ -118,6 +118,8 @@ static int do_pd_setup(struct fs_enet_private *fep)
 
        /* Fill out IRQ field */
        fep->interrupt = platform_get_irq_byname(pdev, "interrupt");
+       if (fep->interrupt < 0)
+               return -EINVAL;
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
        fep->scc.sccp = (void *)r->start;
index 0e8e3fc..771e25d 100644 (file)
@@ -193,8 +193,12 @@ static int gfar_probe(struct platform_device *pdev)
                priv->interruptTransmit = platform_get_irq_byname(pdev, "tx");
                priv->interruptReceive = platform_get_irq_byname(pdev, "rx");
                priv->interruptError = platform_get_irq_byname(pdev, "error");
+               if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0)
+                       goto regs_fail;
        } else {
                priv->interruptTransmit = platform_get_irq(pdev, 0);
+               if (priv->interruptTransmit < 0)
+                       goto regs_fail;
        }
 
        /* get a pointer to the register memory */
index c81fe1c..5e6d007 100644 (file)
@@ -64,6 +64,14 @@ config TEKRAM_DONGLE
          dongles you will have to start irattach like this:
          "irattach -d tekram".
 
+config TOIM3232_DONGLE
+       tristate "TOIM3232 IrDa dongle"
+       depends on DONGLE && IRDA
+       help
+         Say Y here if you want to build support for the Vishay/Temic
+         TOIM3232 and TOIM4232 based dongles.
+         To compile it as a module, choose M here.
+
 config LITELINK_DONGLE
        tristate "Parallax LiteLink dongle"
        depends on DONGLE && IRDA
index 72cbfdc..27ab75f 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_OLD_BELKIN_DONGLE)       += old_belkin-sir.o
 obj-$(CONFIG_MCP2120_DONGLE)   += mcp2120-sir.o
 obj-$(CONFIG_ACT200L_DONGLE)   += act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)     += ma600-sir.o
+obj-$(CONFIG_TOIM3232_DONGLE)  += toim3232-sir.o
 
 # The SIR helper module
 sir-dev-objs := sir_dev.o sir_dongle.o sir_kthread.o
index 3137592..910c0ca 100644 (file)
@@ -1778,7 +1778,7 @@ static struct pci_driver donauboe_pci_driver = {
 static int __init
 donauboe_init (void)
 {
-  return pci_module_init(&donauboe_pci_driver);
+  return pci_register_driver(&donauboe_pci_driver);
 }
 
 static void __exit
index 3189626..4cba38f 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/delay.h>
 #include <linux/tty.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
@@ -23,6 +24,8 @@ static void ep7211_ir_close(dongle_t *self);
 static int  ep7211_ir_change_speed(struct irda_task *task);
 static int  ep7211_ir_reset(struct irda_task *task);
 
+static DEFINE_SPINLOCK(ep7211_lock);
+
 static struct dongle_reg dongle = {
        .type = IRDA_EP7211_IR,
        .open = ep7211_ir_open,
@@ -36,7 +39,7 @@ static void ep7211_ir_open(dongle_t *self, struct qos_info *qos)
 {
        unsigned int syscon1, flags;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&ep7211_lock, flags);
 
        /* Turn on the SIR encoder. */
        syscon1 = clps_readl(SYSCON1);
@@ -46,14 +49,14 @@ static void ep7211_ir_open(dongle_t *self, struct qos_info *qos)
        /* XXX: We should disable modem status interrupts on the first
                UART (interrupt #14). */
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&ep7211_lock, flags);
 }
 
 static void ep7211_ir_close(dongle_t *self)
 {
        unsigned int syscon1, flags;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&ep7211_lock, flags);
 
        /* Turn off the SIR encoder. */
        syscon1 = clps_readl(SYSCON1);
@@ -63,7 +66,7 @@ static void ep7211_ir_close(dongle_t *self)
        /* XXX: If we've disabled the modem status interrupts, we should
                reset them back to their original state. */
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&ep7211_lock, flags);
 }
 
 /*
index 8936058..6e2ec56 100644 (file)
@@ -740,7 +740,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
        struct sk_buff *newskb;
        struct sk_buff *dataskb;
        struct urb *next_urb;
-       int             docopy;
+       unsigned int len, docopy;
 
        IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);
        
@@ -851,10 +851,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
        dataskb->dev = self->netdev;
        dataskb->mac.raw  = dataskb->data;
        dataskb->protocol = htons(ETH_P_IRDA);
+       len = dataskb->len;
        netif_rx(dataskb);
 
        /* Keep stats up to date */
-       self->stats.rx_bytes += dataskb->len;
+       self->stats.rx_bytes += len;
        self->stats.rx_packets++;
        self->netdev->last_rx = jiffies;
 
index 101750b..6a98b7a 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
@@ -338,7 +339,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
 /*****************************************************************/
 
 /* serialize ldisc open/close with sir_dev */
-static DECLARE_MUTEX(irtty_sem);
+static DEFINE_MUTEX(irtty_mutex);
 
 /* notifier from sir_dev when irda% device gets opened (ifup) */
 
@@ -348,11 +349,11 @@ static int irtty_start_dev(struct sir_dev *dev)
        struct tty_struct *tty;
 
        /* serialize with ldisc open/close */
-       down(&irtty_sem);
+       mutex_lock(&irtty_mutex);
 
        priv = dev->priv;
        if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
-               up(&irtty_sem);
+               mutex_unlock(&irtty_mutex);
                return -ESTALE;
        }
 
@@ -363,7 +364,7 @@ static int irtty_start_dev(struct sir_dev *dev)
        /* Make sure we can receive more data */
        irtty_stop_receiver(tty, FALSE);
 
-       up(&irtty_sem);
+       mutex_unlock(&irtty_mutex);
        return 0;
 }
 
@@ -375,11 +376,11 @@ static int irtty_stop_dev(struct sir_dev *dev)
        struct tty_struct *tty;
 
        /* serialize with ldisc open/close */
-       down(&irtty_sem);
+       mutex_lock(&irtty_mutex);
 
        priv = dev->priv;
        if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
-               up(&irtty_sem);
+               mutex_unlock(&irtty_mutex);
                return -ESTALE;
        }
 
@@ -390,7 +391,7 @@ static int irtty_stop_dev(struct sir_dev *dev)
        if (tty->driver->stop)
                tty->driver->stop(tty);
 
-       up(&irtty_sem);
+       mutex_unlock(&irtty_mutex);
 
        return 0;
 }
@@ -514,13 +515,13 @@ static int irtty_open(struct tty_struct *tty)
        priv->dev = dev;
 
        /* serialize with start_dev - in case we were racing with ifup */
-       down(&irtty_sem);
+       mutex_lock(&irtty_mutex);
 
        dev->priv = priv;
        tty->disc_data = priv;
        tty->receive_room = 65536;
 
-       up(&irtty_sem);
+       mutex_unlock(&irtty_mutex);
 
        IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __FUNCTION__, tty->name);
 
index ee717d0..83141a3 100644 (file)
@@ -12,6 +12,7 @@
  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
  *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
  *     Copyright (c) 1998 Actisys Corp., www.actisys.com
+ *     Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com>
  *     All Rights Reserved
  *      
  *     This program is free software; you can redistribute it and/or 
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/dma-mapping.h>
+#include <linux/pnp.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 
-#include <linux/pm.h>
-#include <linux/pm_legacy.h>
-
 #include <net/irda/wrapper.h>
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
 
 static char *driver_name = "nsc-ircc";
 
+/* Power Management */
+#define NSC_IRCC_DRIVER_NAME                  "nsc-ircc"
+static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
+static int nsc_ircc_resume(struct platform_device *dev);
+
+static struct platform_driver nsc_ircc_driver = {
+       .suspend        = nsc_ircc_suspend,
+       .resume         = nsc_ircc_resume,
+       .driver         = {
+               .name   = NSC_IRCC_DRIVER_NAME,
+       },
+};
+
 /* Module parameters */
 static int qos_mtt_bits = 0x07;  /* 1 ms or more */
 static int dongle_id;
 
 /* Use BIOS settions by default, but user may supply module parameters */
-static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
-static unsigned int irq[] = { 0, 0, 0, 0, 0 };
-static unsigned int dma[] = { 0, 0, 0, 0, 0 };
+static unsigned int io[]  = { ~0, ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = {  0,  0,  0,  0,  0 };
+static unsigned int dma[] = {  0,  0,  0,  0,  0 };
 
 static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
@@ -87,6 +100,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
 
 /* These are the known NSC chips */
 static nsc_chip_t chips[] = {
@@ -101,11 +115,12 @@ static nsc_chip_t chips[] = {
        /* Contributed by Jan Frey - IBM A30/A31 */
        { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, 
          nsc_ircc_probe_39x, nsc_ircc_init_39x },
+       { "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
+         nsc_ircc_probe_39x, nsc_ircc_init_39x },
        { NULL }
 };
 
-/* Max 4 instances for now */
-static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
+static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
 
 static char *dongle_types[] = {
        "Differential serial interface",
@@ -126,8 +141,24 @@ static char *dongle_types[] = {
        "No dongle connected",
 };
 
+/* PNP probing */
+static chipio_t pnp_info;
+static const struct pnp_device_id nsc_ircc_pnp_table[] = {
+       { .id = "NSC6001", .driver_data = 0 },
+       { .id = "IBM0071", .driver_data = 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
+
+static struct pnp_driver nsc_ircc_pnp_driver = {
+       .name = "nsc-ircc",
+       .id_table = nsc_ircc_pnp_table,
+       .probe = nsc_ircc_pnp_probe,
+};
+
 /* Some prototypes */
-static int  nsc_ircc_open(int i, chipio_t *info);
+static int  nsc_ircc_open(chipio_t *info);
 static int  nsc_ircc_close(struct nsc_ircc_cb *self);
 static int  nsc_ircc_setup(chipio_t *info);
 static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
@@ -146,7 +177,10 @@ static int  nsc_ircc_net_open(struct net_device *dev);
 static int  nsc_ircc_net_close(struct net_device *dev);
 static int  nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
-static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
+
+/* Globals */
+static int pnp_registered;
+static int pnp_succeeded;
 
 /*
  * Function nsc_ircc_init ()
@@ -158,28 +192,36 @@ static int __init nsc_ircc_init(void)
 {
        chipio_t info;
        nsc_chip_t *chip;
-       int ret = -ENODEV;
+       int ret;
        int cfg_base;
        int cfg, id;
        int reg;
        int i = 0;
 
+       ret = platform_driver_register(&nsc_ircc_driver);
+        if (ret) {
+                IRDA_ERROR("%s, Can't register driver!\n", driver_name);
+                return ret;
+        }
+
+       /* Register with PnP subsystem to detect disable ports */
+       ret = pnp_register_driver(&nsc_ircc_pnp_driver);
+
+       if (ret >= 0)
+               pnp_registered = 1;
+
+       ret = -ENODEV;
+
        /* Probe for all the NSC chipsets we know about */
-       for (chip=chips; chip->name ; chip++) {
+       for (chip = chips; chip->name ; chip++) {
                IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__,
                           chip->name);
                
                /* Try all config registers for this chip */
-               for (cfg=0; cfg<3; cfg++) {
+               for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) {
                        cfg_base = chip->cfg[cfg];
                        if (!cfg_base)
                                continue;
-                       
-                       memset(&info, 0, sizeof(chipio_t));
-                       info.cfg_base = cfg_base;
-                       info.fir_base = io[i];
-                       info.dma = dma[i];
-                       info.irq = irq[i];
 
                        /* Read index register */
                        reg = inb(cfg_base);
@@ -194,24 +236,65 @@ static int __init nsc_ircc_init(void)
                        if ((id & chip->cid_mask) == chip->cid_value) {
                                IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
                                           __FUNCTION__, chip->name, id & ~chip->cid_mask);
-                               /* 
-                                * If the user supplies the base address, then
-                                * we init the chip, if not we probe the values
-                                * set by the BIOS
-                                */                             
-                               if (io[i] < 0x2000) {
-                                       chip->init(chip, &info);
-                               } else
-                                       chip->probe(chip, &info);
 
-                               if (nsc_ircc_open(i, &info) == 0)
-                                       ret = 0;
+                               /*
+                                * If we found a correct PnP setting,
+                                * we first try it.
+                                */
+                               if (pnp_succeeded) {
+                                       memset(&info, 0, sizeof(chipio_t));
+                                       info.cfg_base = cfg_base;
+                                       info.fir_base = pnp_info.fir_base;
+                                       info.dma = pnp_info.dma;
+                                       info.irq = pnp_info.irq;
+
+                                       if (info.fir_base < 0x2000) {
+                                               IRDA_MESSAGE("%s, chip->init\n", driver_name);
+                                               chip->init(chip, &info);
+                                       } else
+                                               chip->probe(chip, &info);
+
+                                       if (nsc_ircc_open(&info) >= 0)
+                                               ret = 0;
+                               }
+
+                               /*
+                                * Opening based on PnP values failed.
+                                * Let's fallback to user values, or probe
+                                * the chip.
+                                */
+                               if (ret) {
+                                       IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name);
+                                       memset(&info, 0, sizeof(chipio_t));
+                                       info.cfg_base = cfg_base;
+                                       info.fir_base = io[i];
+                                       info.dma = dma[i];
+                                       info.irq = irq[i];
+
+                                       /*
+                                        * If the user supplies the base address, then
+                                        * we init the chip, if not we probe the values
+                                        * set by the BIOS
+                                        */
+                                       if (io[i] < 0x2000) {
+                                               chip->init(chip, &info);
+                                       } else
+                                               chip->probe(chip, &info);
+
+                                       if (nsc_ircc_open(&info) >= 0)
+                                               ret = 0;
+                               }
                                i++;
                        } else {
                                IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id);
                        }
                } 
-               
+       }
+
+       if (ret) {
+               platform_driver_unregister(&nsc_ircc_driver);
+               pnp_unregister_driver(&nsc_ircc_pnp_driver);
+               pnp_registered = 0;
        }
 
        return ret;
@@ -227,12 +310,17 @@ static void __exit nsc_ircc_cleanup(void)
 {
        int i;
 
-       pm_unregister_all(nsc_ircc_pmproc);
-
-       for (i=0; i < 4; i++) {
+       for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
                if (dev_self[i])
                        nsc_ircc_close(dev_self[i]);
        }
+
+       platform_driver_unregister(&nsc_ircc_driver);
+
+       if (pnp_registered)
+               pnp_unregister_driver(&nsc_ircc_pnp_driver);
+
+       pnp_registered = 0;
 }
 
 /*
@@ -241,16 +329,26 @@ static void __exit nsc_ircc_cleanup(void)
  *    Open driver instance
  *
  */
-static int __init nsc_ircc_open(int i, chipio_t *info)
+static int __init nsc_ircc_open(chipio_t *info)
 {
        struct net_device *dev;
        struct nsc_ircc_cb *self;
-        struct pm_dev *pmdev;
        void *ret;
-       int err;
+       int err, chip_index;
 
        IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
+
+       for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) {
+               if (!dev_self[chip_index])
+                       break;
+       }
+
+       if (chip_index == ARRAY_SIZE(dev_self)) {
+               IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+
        IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
                     info->cfg_base);
 
@@ -271,8 +369,8 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
        spin_lock_init(&self->lock);
    
        /* Need to store self somewhere */
-       dev_self[i] = self;
-       self->index = i;
+       dev_self[chip_index] = self;
+       self->index = chip_index;
 
        /* Initialize IO */
        self->io.cfg_base  = info->cfg_base;
@@ -351,7 +449,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
 
        /* Check if user has supplied a valid dongle id or not */
        if ((dongle_id <= 0) ||
-           (dongle_id >= (sizeof(dongle_types) / sizeof(dongle_types[0]))) ) {
+           (dongle_id >= ARRAY_SIZE(dongle_types))) {
                dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
                
                IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name,
@@ -364,11 +462,18 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
        self->io.dongle_id = dongle_id;
        nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
 
-        pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc);
-        if (pmdev)
-                pmdev->data = self;
+       self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME,
+                                                     self->index, NULL, 0);
+       if (IS_ERR(self->pldev)) {
+               err = PTR_ERR(self->pldev);
+               goto out5;
+       }
+       platform_set_drvdata(self->pldev, self);
 
-       return 0;
+       return chip_index;
+
+ out5:
+       unregister_netdev(dev);
  out4:
        dma_free_coherent(NULL, self->tx_buff.truesize,
                          self->tx_buff.head, self->tx_buff_dma);
@@ -379,7 +484,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
        release_region(self->io.fir_base, self->io.fir_ext);
  out1:
        free_netdev(dev);
-       dev_self[i] = NULL;
+       dev_self[chip_index] = NULL;
        return err;
 }
 
@@ -399,6 +504,8 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self)
 
         iobase = self->io.fir_base;
 
+       platform_device_unregister(self->pldev);
+
        /* Remove netdevice */
        unregister_netdev(self->netdev);
 
@@ -806,6 +913,43 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info)
        return 0;
 }
 
+/* PNP probing */
+static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
+{
+       memset(&pnp_info, 0, sizeof(chipio_t));
+       pnp_info.irq = -1;
+       pnp_info.dma = -1;
+       pnp_succeeded = 1;
+
+       /* There don't seem to be any way to get the cfg_base.
+        * On my box, cfg_base is in the PnP descriptor of the
+        * motherboard. Oh well... Jean II */
+
+       if (pnp_port_valid(dev, 0) &&
+               !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED))
+               pnp_info.fir_base = pnp_port_start(dev, 0);
+
+       if (pnp_irq_valid(dev, 0) &&
+               !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED))
+               pnp_info.irq = pnp_irq(dev, 0);
+
+       if (pnp_dma_valid(dev, 0) &&
+               !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
+               pnp_info.dma = pnp_dma(dev, 0);
+
+       IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
+                  __FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);
+
+       if((pnp_info.fir_base == 0) ||
+          (pnp_info.irq == -1) || (pnp_info.dma == -1)) {
+               /* Returning an error will disable the device. Yuck ! */
+               //return -EINVAL;
+               pnp_succeeded = 0;
+       }
+
+       return 0;
+}
+
 /*
  * Function nsc_ircc_setup (info)
  *
@@ -2161,45 +2305,83 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
        return &self->stats;
 }
 
-static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
+static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
 {
-       IRDA_MESSAGE("%s, Suspending\n", driver_name);
+       struct nsc_ircc_cb *self = platform_get_drvdata(dev);
+       int bank;
+       unsigned long flags;
+       int iobase = self->io.fir_base;
 
        if (self->io.suspended)
-               return;
+               return 0;
 
-       nsc_ircc_net_close(self->netdev);
+       IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
 
+       rtnl_lock();
+       if (netif_running(self->netdev)) {
+               netif_device_detach(self->netdev);
+               spin_lock_irqsave(&self->lock, flags);
+               /* Save current bank */
+               bank = inb(iobase+BSR);
+
+               /* Disable interrupts */
+               switch_bank(iobase, BANK0);
+               outb(0, iobase+IER);
+
+               /* Restore bank register */
+               outb(bank, iobase+BSR);
+
+               spin_unlock_irqrestore(&self->lock, flags);
+               free_irq(self->io.irq, self->netdev);
+               disable_dma(self->io.dma);
+       }
        self->io.suspended = 1;
+       rtnl_unlock();
+
+       return 0;
 }
 
-static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
+static int nsc_ircc_resume(struct platform_device *dev)
 {
+       struct nsc_ircc_cb *self = platform_get_drvdata(dev);
+       unsigned long flags;
+
        if (!self->io.suspended)
-               return;
+               return 0;
 
+       IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
+
+       rtnl_lock();
        nsc_ircc_setup(&self->io);
-       nsc_ircc_net_open(self->netdev);
-       
-       IRDA_MESSAGE("%s, Waking up\n", driver_name);
+       nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id);
 
+       if (netif_running(self->netdev)) {
+               if (request_irq(self->io.irq, nsc_ircc_interrupt, 0,
+                               self->netdev->name, self->netdev)) {
+                       IRDA_WARNING("%s, unable to allocate irq=%d\n",
+                                    driver_name, self->io.irq);
+
+                       /*
+                        * Don't fail resume process, just kill this
+                        * network interface
+                        */
+                       unregister_netdevice(self->netdev);
+               } else {
+                       spin_lock_irqsave(&self->lock, flags);
+                       nsc_ircc_change_speed(self, self->io.speed);
+                       spin_unlock_irqrestore(&self->lock, flags);
+                       netif_device_attach(self->netdev);
+               }
+
+       } else {
+               spin_lock_irqsave(&self->lock, flags);
+               nsc_ircc_change_speed(self, 9600);
+               spin_unlock_irqrestore(&self->lock, flags);
+       }
        self->io.suspended = 0;
-}
+       rtnl_unlock();
 
-static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-        struct nsc_ircc_cb *self = (struct nsc_ircc_cb*) dev->data;
-        if (self) {
-                switch (rqst) {
-                case PM_SUSPEND:
-                        nsc_ircc_suspend(self);
-                        break;
-                case PM_RESUME:
-                        nsc_ircc_wakeup(self);
-                        break;
-                }
-        }
-       return 0;
+       return 0;
 }
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
index 6edf7e5..dacf671 100644 (file)
@@ -269,7 +269,7 @@ struct nsc_ircc_cb {
        __u32 new_speed;
        int index;                 /* Instance index */
 
-        struct pm_dev *dev;
+       struct platform_device *pldev;
 };
 
 static inline void switch_bank(int iobase, int bank)
index 8d22592..d7e32d9 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/kmod.h>
+#include <linux/mutex.h>
 
 #include <net/irda/irda.h>
 
@@ -28,7 +29,7 @@
  */
 
 static LIST_HEAD(dongle_list);                 /* list of registered dongle drivers */
-static DECLARE_MUTEX(dongle_list_lock);                /* protects the list */
+static DEFINE_MUTEX(dongle_list_lock);         /* protects the list */
 
 int irda_register_dongle(struct dongle_driver *new)
 {
@@ -38,25 +39,25 @@ int irda_register_dongle(struct dongle_driver *new)
        IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n",
                   __FUNCTION__, new->driver_name, new->type);
 
-       down(&dongle_list_lock);
+       mutex_lock(&dongle_list_lock);
        list_for_each(entry, &dongle_list) {
                drv = list_entry(entry, struct dongle_driver, dongle_list);
                if (new->type == drv->type) {
-                       up(&dongle_list_lock);
+                       mutex_unlock(&dongle_list_lock);
                        return -EEXIST;
                }
        }
        list_add(&new->dongle_list, &dongle_list);
-       up(&dongle_list_lock);
+       mutex_unlock(&dongle_list_lock);
        return 0;
 }
 EXPORT_SYMBOL(irda_register_dongle);
 
 int irda_unregister_dongle(struct dongle_driver *drv)
 {
-       down(&dongle_list_lock);
+       mutex_lock(&dongle_list_lock);
        list_del(&drv->dongle_list);
-       up(&dongle_list_lock);
+       mutex_unlock(&dongle_list_lock);
        return 0;
 }
 EXPORT_SYMBOL(irda_unregister_dongle);
@@ -75,7 +76,7 @@ int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
                return -EBUSY;
        
        /* serialize access to the list of registered dongles */
-       down(&dongle_list_lock);
+       mutex_lock(&dongle_list_lock);
 
        list_for_each(entry, &dongle_list) {
                drv = list_entry(entry, struct dongle_driver, dongle_list);
@@ -109,14 +110,14 @@ int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
        if (!drv->open  ||  (err=drv->open(dev))!=0)
                goto out_reject;                /* failed to open driver */
 
-       up(&dongle_list_lock);
+       mutex_unlock(&dongle_list_lock);
        return 0;
 
 out_reject:
        dev->dongle_drv = NULL;
        module_put(drv->owner);
 out_unlock:
-       up(&dongle_list_lock);
+       mutex_unlock(&dongle_list_lock);
        return err;
 }
 
diff --git a/drivers/net/irda/toim3232-sir.c b/drivers/net/irda/toim3232-sir.c
new file mode 100644 (file)
index 0000000..aa1a9b0
--- /dev/null
@@ -0,0 +1,375 @@
+/*********************************************************************
+ *
+ * Filename:      toim3232-sir.c
+ * Version:       1.0
+ * Description:   Implementation of dongles based on the Vishay/Temic
+ *               TOIM3232 SIR Endec chipset. Currently only the
+ *               IRWave IR320ST-2 is tested, although it should work
+ *               with any TOIM3232 or TOIM4232 chipset based RS232
+ *               dongle with minimal modification.
+ *               Based heavily on the Tekram driver (tekram.c),
+ *               with thanks to Dag Brattli and Martin Diehl.
+ * Status:        Experimental.
+ * Author:        David Basden <davidb-irda@rcpt.to>
+ * Created at:    Thu Feb 09 23:47:32 2006
+ *
+ *     Copyright (c) 2006 David Basden.
+ *     Copyright (c) 1998-1999 Dag Brattli,
+ *     Copyright (c) 2002 Martin Diehl,
+ *     All Rights Reserved.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     provide warranty for any of this software. This material is
+ *     provided "AS-IS" and at no charge.
+ *
+ ********************************************************************/
+
+/*
+ * This driver has currently only been tested on the IRWave IR320ST-2
+ *
+ * PROTOCOL:
+ *
+ * The protocol for talking to the TOIM3232 is quite easy, and is
+ * designed to interface with RS232 with only level convertors. The
+ * BR/~D line on the chip is brought high to signal 'command mode',
+ * where a command byte is sent to select the baudrate of the RS232
+ * interface and the pulse length of the IRDA output. When BR/~D
+ * is brought low, the dongle then changes to the selected baudrate,
+ * and the RS232 interface is used for data until BR/~D is brought
+ * high again. The initial speed for the TOIMx323 after RESET is
+ * 9600 baud.  The baudrate for command-mode is the last selected
+ * baud-rate, or 9600 after a RESET.
+ *
+ * The  dongle I have (below) adds some extra hardware on the front end,
+ * but this is mostly directed towards pariasitic power from the RS232
+ * line rather than changing very much about how to communicate with
+ * the TOIM3232.
+ *
+ * The protocol to talk to the TOIM4232 chipset seems to be almost
+ * identical to the TOIM3232 (and the 4232 datasheet is more detailed)
+ * so this code will probably work on that as well, although I haven't
+ * tested it on that hardware.
+ *
+ * Target dongle variations that might be common:
+ *
+ * DTR and RTS function:
+ *   The data sheet for the 4232 has a sample implementation that hooks the
+ *   DTR and RTS lines to the RESET and BaudRate/~Data lines of the
+ *   chip (through line-converters). Given both DTR and RTS would have to
+ *   be held low in normal operation, and the TOIMx232 requires +5V to
+ *   signal ground, most dongle designers would almost certainly choose
+ *   an implementation that kept at least one of DTR or RTS high in
+ *   normal operation to provide power to the dongle, but will likely
+ *   vary between designs.
+ *
+ * User specified command bits:
+ *  There are two user-controllable output lines from the TOIMx232 that
+ *  can be set low or high by setting the appropriate bits in the
+ *  high-nibble of the command byte (when setting speed and pulse length).
+ *  These might be used to switch on and off added hardware or extra
+ *  dongle features.
+ *
+ *
+ * Target hardware: IRWave IR320ST-2
+ *
+ *     The IRWave IR320ST-2 is a simple dongle based on the Vishay/Temic
+ *     TOIM3232 SIR Endec and the Vishay/Temic TFDS4500 SIR IRDA transciever.
+ *     It uses a hex inverter and some discrete components to buffer and
+ *     line convert the RS232 down to 5V.
+ *
+ *     The dongle is powered through a voltage regulator, fed by a large
+ *     capacitor. To switch the dongle on, DTR is brought high to charge
+ *     the capacitor and drive the voltage regulator. DTR isn't associated
+ *     with any control lines on the TOIM3232. Parisitic power is also taken
+ *     from the RTS, TD and RD lines when brought high, but through resistors.
+ *     When DTR is low, the circuit might lose power even with RTS high.
+ *
+ *     RTS is inverted and attached to the BR/~D input pin. When RTS
+ *     is high, BR/~D is low, and the TOIM3232 is in the normal 'data' mode.
+ *     RTS is brought low, BR/~D is high, and the TOIM3232 is in 'command
+ *     mode'.
+ *
+ *     For some unknown reason, the RESET line isn't actually connected
+ *     to anything. This means to reset the dongle to get it to a known
+ *     state (9600 baud) you must drop DTR and RTS low, wait for the power
+ *     capacitor to discharge, and then bring DTR (and RTS for data mode)
+ *     high again, and wait for the capacitor to charge, the power supply
+ *     to stabilise, and the oscillator clock to stabilise.
+ *
+ *     Fortunately, if the current baudrate is known, the chipset can
+ *     easily change speed by entering command mode without having to
+ *     reset the dongle first.
+ *
+ *     Major Components:
+ *
+ *     - Vishay/Temic TOIM3232 SIR Endec to change RS232 pulse timings
+ *       to IRDA pulse timings
+ *     - 3.6864MHz crystal to drive TOIM3232 clock oscillator
+ *     - DM74lS04M Inverting Hex line buffer for RS232 input buffering
+ *       and level conversion
+ *     - PJ2951AC 150mA voltage regulator
+ *     - Vishay/Temic TFDS4500 SIR IRDA front-end transceiver
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+
+#include "sir-dev.h"
+
+static int toim3232delay = 150;        /* default is 150 ms */
+module_param(toim3232delay, int, 0);
+MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay");
+
+#if 0
+static int toim3232flipdtr = 0;        /* default is DTR high to reset */
+module_param(toim3232flipdtr, int, 0);
+MODULE_PARM_DESC(toim3232flipdtr, "toim3232 dongle invert DTR (Reset)");
+
+static int toim3232fliprts = 0;        /* default is RTS high for baud change */
+module_param(toim3232fliptrs, int, 0);
+MODULE_PARM_DESC(toim3232fliprts, "toim3232 dongle invert RTS (BR/D)");
+#endif
+
+static int toim3232_open(struct sir_dev *);
+static int toim3232_close(struct sir_dev *);
+static int toim3232_change_speed(struct sir_dev *, unsigned);
+static int toim3232_reset(struct sir_dev *);
+
+#define TOIM3232_115200 0x00
+#define TOIM3232_57600  0x01
+#define TOIM3232_38400  0x02
+#define TOIM3232_19200  0x03
+#define TOIM3232_9600   0x06
+#define TOIM3232_2400   0x0A
+
+#define TOIM3232_PW     0x10 /* Pulse select bit */
+
+static struct dongle_driver toim3232 = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "Vishay TOIM3232",
+       .type           = IRDA_TOIM3232_DONGLE,
+       .open           = toim3232_open,
+       .close          = toim3232_close,
+       .reset          = toim3232_reset,
+       .set_speed      = toim3232_change_speed,
+};
+
+static int __init toim3232_sir_init(void)
+{
+       if (toim3232delay < 1  ||  toim3232delay > 500)
+               toim3232delay = 200;
+       IRDA_DEBUG(1, "%s - using %d ms delay\n",
+               toim3232.driver_name, toim3232delay);
+       return irda_register_dongle(&toim3232);
+}
+
+static void __exit toim3232_sir_cleanup(void)
+{
+       irda_unregister_dongle(&toim3232);
+}
+
+static int toim3232_open(struct sir_dev *dev)
+{
+       struct qos_info *qos = &dev->qos;
+
+       IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+       /* Pull the lines high to start with.
+        *
+        * For the IR320ST-2, we need to charge the main supply capacitor to
+        * switch the device on. We keep DTR high throughout to do this.
+        * When RTS, TD and RD are high, they will also trickle-charge the
+        * cap. RTS is high for data transmission, and low for baud rate select.
+        *      -- DGB
+        */
+       sirdev_set_dtr_rts(dev, TRUE, TRUE);
+
+       /* The TOI3232 supports many speeds between 1200bps and 115000bps.
+        * We really only care about those supported by the IRDA spec, but
+        * 38400 seems to be implemented in many places */
+       qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+
+       /* From the tekram driver. Not sure what a reasonable value is -- DGB */
+       qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
+       irda_qos_bits_to_value(qos);
+
+       /* irda thread waits 50 msec for power settling */
+
+       return 0;
+}
+
+static int toim3232_close(struct sir_dev *dev)
+{
+       IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+       /* Power off dongle */
+       sirdev_set_dtr_rts(dev, FALSE, FALSE);
+
+       return 0;
+}
+
+/*
+ * Function toim3232change_speed (dev, state, speed)
+ *
+ *    Set the speed for the TOIM3232 based dongle. Warning, this
+ *    function must be called with a process context!
+ *
+ *    Algorithm
+ *    1. keep DTR high but clear RTS to bring into baud programming mode
+ *    2. wait at least 7us to enter programming mode
+ *    3. send control word to set baud rate and timing
+ *    4. wait at least 1us
+ *    5. bring RTS high to enter DATA mode (RS232 is passed through to transceiver)
+ *    6. should take effect immediately (although probably worth waiting)
+ */
+
+#define TOIM3232_STATE_WAIT_SPEED      (SIRDEV_STATE_DONGLE_SPEED + 1)
+
+static int toim3232_change_speed(struct sir_dev *dev, unsigned speed)
+{
+       unsigned state = dev->fsm.substate;
+       unsigned delay = 0;
+       u8 byte;
+       static int ret = 0;
+
+       IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+       switch(state) {
+       case SIRDEV_STATE_DONGLE_SPEED:
+
+               /* Figure out what we are going to send as a control byte */
+               switch (speed) {
+               case 2400:
+                       byte = TOIM3232_PW|TOIM3232_2400;
+                       break;
+               default:
+                       speed = 9600;
+                       ret = -EINVAL;
+                       /* fall thru */
+               case 9600:
+                       byte = TOIM3232_PW|TOIM3232_9600;
+                       break;
+               case 19200:
+                       byte = TOIM3232_PW|TOIM3232_19200;
+                       break;
+               case 38400:
+                       byte = TOIM3232_PW|TOIM3232_38400;
+                       break;
+               case 57600:
+                       byte = TOIM3232_PW|TOIM3232_57600;
+                       break;
+               case 115200:
+                       byte = TOIM3232_115200;
+                       break;
+               }
+
+               /* Set DTR, Clear RTS: Go into baud programming mode */
+               sirdev_set_dtr_rts(dev, TRUE, FALSE);
+
+               /* Wait at least 7us */
+               udelay(14);
+
+               /* Write control byte */
+               sirdev_raw_write(dev, &byte, 1);
+
+               dev->speed = speed;
+
+               state = TOIM3232_STATE_WAIT_SPEED;
+               delay = toim3232delay;
+               break;
+
+       case TOIM3232_STATE_WAIT_SPEED:
+               /* Have transmitted control byte * Wait for 'at least 1us' */
+               udelay(14);
+
+               /* Set DTR, Set RTS: Go into normal data mode */
+               sirdev_set_dtr_rts(dev, TRUE, TRUE);
+
+               /* Wait (TODO: check this is needed) */
+               udelay(50);
+               break;
+
+       default:
+               printk(KERN_ERR "%s - undefined state %d\n", __FUNCTION__, state);
+               ret = -EINVAL;
+               break;
+       }
+
+       dev->fsm.substate = state;
+       return (delay > 0) ? delay : ret;
+}
+
+/*
+ * Function toim3232reset (driver)
+ *
+ *      This function resets the toim3232 dongle. Warning, this function
+ *      must be called with a process context!!
+ *
+ * What we should do is:
+ *     0. Pull RESET high
+ *     1. Wait for at least 7us
+ *     2. Pull RESET low
+ *     3. Wait for at least 7us
+ *     4. Pull BR/~D high
+ *     5. Wait for at least 7us
+ *     6. Send control byte to set baud rate
+ *     7. Wait at least 1us after stop bit
+ *     8. Pull BR/~D low
+ *     9. Should then be in data mode
+ *
+ * Because the IR320ST-2 doesn't have the RESET line connected for some reason,
+ * we'll have to do something else.
+ *
+ * The default speed after a RESET is 9600, so lets try just bringing it up in
+ * data mode after switching it off, waiting for the supply capacitor to
+ * discharge, and then switch it back on. This isn't actually pulling RESET
+ * high, but it seems to have the same effect.
+ *
+ * This behaviour will probably work on dongles that have the RESET line connected,
+ * but if not, add a flag for the IR320ST-2, and implment the above-listed proper
+ * behaviour.
+ *
+ * RTS is inverted and then fed to BR/~D, so to put it in programming mode, we
+ * need to have pull RTS low
+ */
+
+static int toim3232_reset(struct sir_dev *dev)
+{
+       IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+       /* Switch off both DTR and RTS to switch off dongle */
+       sirdev_set_dtr_rts(dev, FALSE, FALSE);
+
+       /* Should sleep a while. This might be evil doing it this way.*/
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(msecs_to_jiffies(50));
+
+       /* Set DTR, Set RTS (data mode) */
+       sirdev_set_dtr_rts(dev, TRUE, TRUE);
+
+       /* Wait at least 10 ms for power to stabilize again */
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(msecs_to_jiffies(10));
+
+       /* Speed should now be 9600 */
+       dev->speed = 9600;
+
+       return 0;
+}
+
+MODULE_AUTHOR("David Basden <davidb-linux@rcpt.to>");
+MODULE_DESCRIPTION("Vishay/Temic TOIM3232 based dongle driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("irda-dongle-12"); /* IRDA_TOIM3232_DONGLE */
+
+module_init(toim3232_sir_init);
+module_exit(toim3232_sir_cleanup);
index a9f49f0..97a49e0 100644 (file)
@@ -1887,7 +1887,7 @@ static int __init vlsi_mod_init(void)
                vlsi_proc_root->owner = THIS_MODULE;
        }
 
-       ret = pci_module_init(&vlsi_irda_driver);
+       ret = pci_register_driver(&vlsi_irda_driver);
 
        if (ret && vlsi_proc_root)
                remove_proc_entry(PROC_DIR, NULL);
index 0245e40..f608c12 100644 (file)
@@ -1691,8 +1691,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
                    || ppp->npmode[npi] != NPMODE_PASS) {
                        kfree_skb(skb);
                } else {
-                       skb_pull(skb, 2);       /* chop off protocol */
-                       skb_postpull_rcsum(skb, skb->data - 2, 2);
+                       /* chop off protocol */
+                       skb_pull_rcsum(skb, 2);
                        skb->dev = ppp->dev;
                        skb->protocol = htons(npindex_to_ethertype[npi]);
                        skb->mac.raw = skb->data;
index 9369f81..475dc93 100644 (file)
@@ -337,8 +337,7 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
        if (sk->sk_state & PPPOX_BOUND) {
                struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw;
                int len = ntohs(ph->length);
-               skb_pull(skb, sizeof(struct pppoe_hdr));
-               skb_postpull_rcsum(skb, ph, sizeof(*ph));
+               skb_pull_rcsum(skb, sizeof(struct pppoe_hdr));
                if (pskb_trim_rcsum(skb, len))
                        goto abort_kfree;
 
index 7ec0812..75e9b3b 100644 (file)
@@ -2221,6 +2221,10 @@ static int smc_drv_probe(struct platform_device *pdev)
 
        ndev->dma = (unsigned char)-1;
        ndev->irq = platform_get_irq(pdev, 0);
+       if (ndev->irq < 0) {
+               ret = -ENODEV;
+               goto out_free_netdev;
+       }
 
        ret = smc_request_attrib(pdev);
        if (ret)
index 28ce47a..38cd30c 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/workqueue.h>
 #include <linux/if_vlan.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -2284,7 +2285,7 @@ static void gem_reset_task(void *data)
 {
        struct gem *gp = (struct gem *) data;
 
-       down(&gp->pm_sem);
+       mutex_lock(&gp->pm_mutex);
 
        netif_poll_disable(gp->dev);
 
@@ -2311,7 +2312,7 @@ static void gem_reset_task(void *data)
 
        netif_poll_enable(gp->dev);
 
-       up(&gp->pm_sem);
+       mutex_unlock(&gp->pm_mutex);
 }
 
 
@@ -2320,14 +2321,14 @@ static int gem_open(struct net_device *dev)
        struct gem *gp = dev->priv;
        int rc = 0;
 
-       down(&gp->pm_sem);
+       mutex_lock(&gp->pm_mutex);
 
        /* We need the cell enabled */
        if (!gp->asleep)
                rc = gem_do_start(dev);
        gp->opened = (rc == 0);
 
-       up(&gp->pm_sem);
+       mutex_unlock(&gp->pm_mutex);
 
        return rc;
 }
@@ -2340,13 +2341,13 @@ static int gem_close(struct net_device *dev)
         * our caller (dev_close) already did it for us
         */
 
-       down(&gp->pm_sem);
+       mutex_lock(&gp->pm_mutex);
 
        gp->opened = 0; 
        if (!gp->asleep)
                gem_do_stop(dev, 0);
 
-       up(&gp->pm_sem);
+       mutex_unlock(&gp->pm_mutex);
        
        return 0;
 }
@@ -2358,7 +2359,7 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
        struct gem *gp = dev->priv;
        unsigned long flags;
 
-       down(&gp->pm_sem);
+       mutex_lock(&gp->pm_mutex);
 
        netif_poll_disable(dev);
 
@@ -2391,11 +2392,11 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
        /* Stop the link timer */
        del_timer_sync(&gp->link_timer);
 
-       /* Now we release the semaphore to not block the reset task who
+       /* Now we release the mutex to not block the reset task who
         * can take it too. We are marked asleep, so there will be no
         * conflict here
         */
-       up(&gp->pm_sem);
+       mutex_unlock(&gp->pm_mutex);
 
        /* Wait for a pending reset task to complete */
        while (gp->reset_task_pending)
@@ -2424,7 +2425,7 @@ static int gem_resume(struct pci_dev *pdev)
 
        printk(KERN_INFO "%s: resuming\n", dev->name);
 
-       down(&gp->pm_sem);
+       mutex_lock(&gp->pm_mutex);
 
        /* Keep the cell enabled during the entire operation, no need to
         * take a lock here tho since nothing else can happen while we are
@@ -2440,7 +2441,7 @@ static int gem_resume(struct pci_dev *pdev)
                 * still asleep, a new sleep cycle may bring it back
                 */
                gem_put_cell(gp);
-               up(&gp->pm_sem);
+               mutex_unlock(&gp->pm_mutex);
                return 0;
        }
        pci_set_master(gp->pdev);
@@ -2486,7 +2487,7 @@ static int gem_resume(struct pci_dev *pdev)
 
        netif_poll_enable(dev);
        
-       up(&gp->pm_sem);
+       mutex_unlock(&gp->pm_mutex);
 
        return 0;
 }
@@ -2591,7 +2592,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu)
                return 0;
        }
 
-       down(&gp->pm_sem);
+       mutex_lock(&gp->pm_mutex);
        spin_lock_irq(&gp->lock);
        spin_lock(&gp->tx_lock);
        dev->mtu = new_mtu;
@@ -2602,7 +2603,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu)
        }
        spin_unlock(&gp->tx_lock);
        spin_unlock_irq(&gp->lock);
-       up(&gp->pm_sem);
+       mutex_unlock(&gp->pm_mutex);
 
        return 0;
 }
@@ -2771,10 +2772,10 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        int rc = -EOPNOTSUPP;
        unsigned long flags;
 
-       /* Hold the PM semaphore while doing ioctl's or we may collide
+       /* Hold the PM mutex while doing ioctl's or we may collide
         * with power management.
         */
-       down(&gp->pm_sem);
+       mutex_lock(&gp->pm_mutex);
                
        spin_lock_irqsave(&gp->lock, flags);
        gem_get_cell(gp);
@@ -2812,7 +2813,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        gem_put_cell(gp);
        spin_unlock_irqrestore(&gp->lock, flags);
 
-       up(&gp->pm_sem);
+       mutex_unlock(&gp->pm_mutex);
        
        return rc;
 }
@@ -3033,7 +3034,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
 
        spin_lock_init(&gp->lock);
        spin_lock_init(&gp->tx_lock);
-       init_MUTEX(&gp->pm_sem);
+       mutex_init(&gp->pm_mutex);
 
        init_timer(&gp->link_timer);
        gp->link_timer.function = gem_link_timer;
index 13006d7..8984721 100644 (file)
@@ -980,15 +980,15 @@ struct gem {
        int                     tx_new, tx_old;
 
        unsigned int has_wol : 1;       /* chip supports wake-on-lan */
-       unsigned int asleep : 1;        /* chip asleep, protected by pm_sem */
+       unsigned int asleep : 1;        /* chip asleep, protected by pm_mutex */
        unsigned int asleep_wol : 1;    /* was asleep with WOL enabled */
-       unsigned int opened : 1;        /* driver opened, protected by pm_sem */
+       unsigned int opened : 1;        /* driver opened, protected by pm_mutex */
        unsigned int running : 1;       /* chip running, protected by lock */
        
        /* cell enable count, protected by lock */
        int                     cell_enabled;  
        
-       struct semaphore        pm_sem;
+       struct mutex            pm_mutex;
 
        u32                     msg_enable;
        u32                     status;
index 6c6c549..e03d1ae 100644 (file)
@@ -69,8 +69,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.49"
-#define DRV_MODULE_RELDATE     "Feb 2, 2006"
+#define DRV_MODULE_VERSION     "3.52"
+#define DRV_MODULE_RELDATE     "Mar 06, 2006"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -221,10 +221,22 @@ static struct pci_device_id tg3_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S,
@@ -534,6 +546,9 @@ static void tg3_enable_ints(struct tg3 *tp)
             (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
        tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
                       (tp->last_tag << 24));
+       if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
+               tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+                              (tp->last_tag << 24));
        tg3_cond_int(tp);
 }
 
@@ -1038,9 +1053,11 @@ static void tg3_frob_aux_power(struct tg3 *tp)
                struct net_device *dev_peer;
 
                dev_peer = pci_get_drvdata(tp->pdev_peer);
+               /* remove_one() may have been run on the peer. */
                if (!dev_peer)
-                       BUG();
-               tp_peer = netdev_priv(dev_peer);
+                       tp_peer = tp;
+               else
+                       tp_peer = netdev_priv(dev_peer);
        }
 
        if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 ||
@@ -1131,7 +1148,7 @@ static int tg3_halt_cpu(struct tg3 *, u32);
 static int tg3_nvram_lock(struct tg3 *);
 static void tg3_nvram_unlock(struct tg3 *);
 
-static int tg3_set_power_state(struct tg3 *tp, int state)
+static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
 {
        u32 misc_host_ctrl;
        u16 power_control, power_caps;
@@ -1150,7 +1167,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
        power_control |= PCI_PM_CTRL_PME_STATUS;
        power_control &= ~(PCI_PM_CTRL_STATE_MASK);
        switch (state) {
-       case 0:
+       case PCI_D0:
                power_control |= 0;
                pci_write_config_word(tp->pdev,
                                      pm + PCI_PM_CTRL,
@@ -1163,15 +1180,15 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
 
                return 0;
 
-       case 1:
+       case PCI_D1:
                power_control |= 1;
                break;
 
-       case 2:
+       case PCI_D2:
                power_control |= 2;
                break;
 
-       case 3:
+       case PCI_D3hot:
                power_control |= 3;
                break;
 
@@ -2680,6 +2697,12 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
 
        err |= tg3_readphy(tp, MII_BMSR, &bmsr);
        err |= tg3_readphy(tp, MII_BMSR, &bmsr);
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+               if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
+                       bmsr |= BMSR_LSTATUS;
+               else
+                       bmsr &= ~BMSR_LSTATUS;
+       }
 
        err |= tg3_readphy(tp, MII_BMCR, &bmcr);
 
@@ -2748,6 +2771,13 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                        bmcr = new_bmcr;
                        err |= tg3_readphy(tp, MII_BMSR, &bmsr);
                        err |= tg3_readphy(tp, MII_BMSR, &bmsr);
+                       if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
+                           ASIC_REV_5714) {
+                               if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
+                                       bmsr |= BMSR_LSTATUS;
+                               else
+                                       bmsr &= ~BMSR_LSTATUS;
+                       }
                        tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
                }
        }
@@ -3338,6 +3368,23 @@ static inline void tg3_full_unlock(struct tg3 *tp)
        spin_unlock_bh(&tp->lock);
 }
 
+/* One-shot MSI handler - Chip automatically disables interrupt
+ * after sending MSI so driver doesn't have to do it.
+ */
+static irqreturn_t tg3_msi_1shot(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct net_device *dev = dev_id;
+       struct tg3 *tp = netdev_priv(dev);
+
+       prefetch(tp->hw_status);
+       prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
+
+       if (likely(!tg3_irq_sync(tp)))
+               netif_rx_schedule(dev);         /* schedule NAPI poll */
+
+       return IRQ_HANDLED;
+}
+
 /* MSI ISR - No need to check for interrupt sharing and no need to
  * flush status block and interrupt mailbox. PCI ordering rules
  * guarantee that MSI will arrive after the status block.
@@ -3628,11 +3675,139 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
        txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
 }
 
+/* hard_start_xmit for devices that don't have any bugs and
+ * support TG3_FLG2_HW_TSO_2 only.
+ */
 static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
        dma_addr_t mapping;
        u32 len, entry, base_flags, mss;
+
+       len = skb_headlen(skb);
+
+       /* No BH disabling for tx_lock here.  We are running in BH disabled
+        * context and TX reclaim runs via tp->poll inside of a software
+        * interrupt.  Furthermore, IRQ processing runs lockless so we have
+        * no IRQ context deadlocks to worry about either.  Rejoice!
+        */
+       if (!spin_trylock(&tp->tx_lock))
+               return NETDEV_TX_LOCKED;
+
+       if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+               if (!netif_queue_stopped(dev)) {
+                       netif_stop_queue(dev);
+
+                       /* This is a hard error, log it. */
+                       printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
+                              "queue awake!\n", dev->name);
+               }
+               spin_unlock(&tp->tx_lock);
+               return NETDEV_TX_BUSY;
+       }
+
+       entry = tp->tx_prod;
+       base_flags = 0;
+#if TG3_TSO_SUPPORT != 0
+       mss = 0;
+       if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
+           (mss = skb_shinfo(skb)->tso_size) != 0) {
+               int tcp_opt_len, ip_tcp_len;
+
+               if (skb_header_cloned(skb) &&
+                   pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+                       dev_kfree_skb(skb);
+                       goto out_unlock;
+               }
+
+               tcp_opt_len = ((skb->h.th->doff - 5) * 4);
+               ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+
+               base_flags |= (TXD_FLAG_CPU_PRE_DMA |
+                              TXD_FLAG_CPU_POST_DMA);
+
+               skb->nh.iph->check = 0;
+               skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
+
+               skb->h.th->check = 0;
+
+               mss |= (ip_tcp_len + tcp_opt_len) << 9;
+       }
+       else if (skb->ip_summed == CHECKSUM_HW)
+               base_flags |= TXD_FLAG_TCPUDP_CSUM;
+#else
+       mss = 0;
+       if (skb->ip_summed == CHECKSUM_HW)
+               base_flags |= TXD_FLAG_TCPUDP_CSUM;
+#endif
+#if TG3_VLAN_TAG_USED
+       if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
+               base_flags |= (TXD_FLAG_VLAN |
+                              (vlan_tx_tag_get(skb) << 16));
+#endif
+
+       /* Queue skb data, a.k.a. the main skb fragment. */
+       mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+
+       tp->tx_buffers[entry].skb = skb;
+       pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
+
+       tg3_set_txd(tp, entry, mapping, len, base_flags,
+                   (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
+
+       entry = NEXT_TX(entry);
+
+       /* Now loop through additional data fragments, and queue them. */
+       if (skb_shinfo(skb)->nr_frags > 0) {
+               unsigned int i, last;
+
+               last = skb_shinfo(skb)->nr_frags - 1;
+               for (i = 0; i <= last; i++) {
+                       skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+                       len = frag->size;
+                       mapping = pci_map_page(tp->pdev,
+                                              frag->page,
+                                              frag->page_offset,
+                                              len, PCI_DMA_TODEVICE);
+
+                       tp->tx_buffers[entry].skb = NULL;
+                       pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
+
+                       tg3_set_txd(tp, entry, mapping, len,
+                                   base_flags, (i == last) | (mss << 1));
+
+                       entry = NEXT_TX(entry);
+               }
+       }
+
+       /* Packets are ready, update Tx producer idx local and on card. */
+       tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
+
+       tp->tx_prod = entry;
+       if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) {
+               netif_stop_queue(dev);
+               if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)
+                       netif_wake_queue(tp->dev);
+       }
+
+out_unlock:
+       mmiowb();
+       spin_unlock(&tp->tx_lock);
+
+       dev->trans_start = jiffies;
+
+       return NETDEV_TX_OK;
+}
+
+/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
+ * support TG3_FLG2_HW_TSO_1 or firmware TSO only.
+ */
+static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
+{
+       struct tg3 *tp = netdev_priv(dev);
+       dma_addr_t mapping;
+       u32 len, entry, base_flags, mss;
        int would_hit_hwbug;
 
        len = skb_headlen(skb);
@@ -4369,6 +4544,10 @@ static int tg3_chip_reset(struct tg3 *tp)
                tp->nvram_lock_cnt = 0;
        }
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+               tw32(GRC_FASTBOOT_PC, 0);
+
        /*
         * We must avoid the readl() that normally takes place.
         * It locks machines, causes machine checks, and other
@@ -5518,6 +5697,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
 
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
+       if (!netif_running(dev))
+               return 0;
+
        spin_lock_bh(&tp->lock);
        __tg3_set_mac_addr(tp);
        spin_unlock_bh(&tp->lock);
@@ -5585,6 +5767,9 @@ static int tg3_reset_hw(struct tg3 *tp)
                tg3_abort_hw(tp, 1);
        }
 
+       if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+               tg3_phy_reset(tp);
+
        err = tg3_chip_reset(tp);
        if (err)
                return err;
@@ -5993,6 +6178,10 @@ static int tg3_reset_hw(struct tg3 *tp)
                }
        }
 
+       /* Enable host coalescing bug fix */
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+               val |= (1 << 29);
+
        tw32_f(WDMAC_MODE, val);
        udelay(40);
 
@@ -6097,6 +6286,17 @@ static int tg3_reset_hw(struct tg3 *tp)
                tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG;
        }
 
+       if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) &&
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) {
+               u32 tmp;
+
+               tmp = tr32(SERDES_RX_CTRL);
+               tw32(SERDES_RX_CTRL, tmp | SERDES_RX_SIG_DETECT);
+               tp->grc_local_ctrl &= ~GRC_LCLCTRL_USE_EXT_SIG_DETECT;
+               tp->grc_local_ctrl |= GRC_LCLCTRL_USE_SIG_DETECT;
+               tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+       }
+
        err = tg3_setup_phy(tp, 1);
        if (err)
                return err;
@@ -6175,7 +6375,7 @@ static int tg3_init_hw(struct tg3 *tp)
        int err;
 
        /* Force the chip into D0. */
-       err = tg3_set_power_state(tp, 0);
+       err = tg3_set_power_state(tp, PCI_D0);
        if (err)
                goto out;
 
@@ -6331,6 +6531,26 @@ static void tg3_timer(unsigned long __opaque)
        add_timer(&tp->timer);
 }
 
+static int tg3_request_irq(struct tg3 *tp)
+{
+       irqreturn_t (*fn)(int, void *, struct pt_regs *);
+       unsigned long flags;
+       struct net_device *dev = tp->dev;
+
+       if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+               fn = tg3_msi;
+               if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
+                       fn = tg3_msi_1shot;
+               flags = SA_SAMPLE_RANDOM;
+       } else {
+               fn = tg3_interrupt;
+               if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+                       fn = tg3_interrupt_tagged;
+               flags = SA_SHIRQ | SA_SAMPLE_RANDOM;
+       }
+       return (request_irq(tp->pdev->irq, fn, flags, dev->name, dev));
+}
+
 static int tg3_test_interrupt(struct tg3 *tp)
 {
        struct net_device *dev = tp->dev;
@@ -6367,16 +6587,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
 
        free_irq(tp->pdev->irq, dev);
        
-       if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
-               err = request_irq(tp->pdev->irq, tg3_msi,
-                                 SA_SAMPLE_RANDOM, dev->name, dev);
-       else {
-               irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
-               if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
-                       fn = tg3_interrupt_tagged;
-               err = request_irq(tp->pdev->irq, fn,
-                                 SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
-       }
+       err = tg3_request_irq(tp);
 
        if (err)
                return err;
@@ -6428,14 +6639,7 @@ static int tg3_test_msi(struct tg3 *tp)
 
        tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
 
-       {
-               irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
-               if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
-                       fn = tg3_interrupt_tagged;
-
-               err = request_irq(tp->pdev->irq, fn,
-                                 SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
-       }
+       err = tg3_request_irq(tp);
        if (err)
                return err;
 
@@ -6462,6 +6666,10 @@ static int tg3_open(struct net_device *dev)
 
        tg3_full_lock(tp, 0);
 
+       err = tg3_set_power_state(tp, PCI_D0);
+       if (err)
+               return err;
+
        tg3_disable_ints(tp);
        tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
 
@@ -6476,7 +6684,9 @@ static int tg3_open(struct net_device *dev)
 
        if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
            (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) &&
-           (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX)) {
+           (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX) &&
+           !((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) &&
+             (tp->pdev_peer == tp->pdev))) {
                /* All MSI supporting chips should support tagged
                 * status.  Assert that this is the case.
                 */
@@ -6491,17 +6701,7 @@ static int tg3_open(struct net_device *dev)
                        tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
                }
        }
-       if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
-               err = request_irq(tp->pdev->irq, tg3_msi,
-                                 SA_SAMPLE_RANDOM, dev->name, dev);
-       else {
-               irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt;
-               if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
-                       fn = tg3_interrupt_tagged;
-
-               err = request_irq(tp->pdev->irq, fn,
-                                 SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
-       }
+       err = tg3_request_irq(tp);
 
        if (err) {
                if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
@@ -6566,6 +6766,14 @@ static int tg3_open(struct net_device *dev)
 
                        return err;
                }
+
+               if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+                       if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) {
+                               u32 val = tr32(0x7c04);
+
+                               tw32(0x7c04, val | (1 << 29));
+                       }
+               }
        }
 
        tg3_full_lock(tp, 0);
@@ -6839,7 +7047,6 @@ static int tg3_close(struct net_device *dev)
        tp->tg3_flags &=
                ~(TG3_FLAG_INIT_COMPLETE |
                  TG3_FLAG_GOT_SERDES_FLOWCTL);
-       netif_carrier_off(tp->dev);
 
        tg3_full_unlock(tp);
 
@@ -6856,6 +7063,10 @@ static int tg3_close(struct net_device *dev)
 
        tg3_free_consistent(tp);
 
+       tg3_set_power_state(tp, PCI_D3hot);
+
+       netif_carrier_off(tp->dev);
+
        return 0;
 }
 
@@ -7150,6 +7361,9 @@ static void tg3_set_rx_mode(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
 
+       if (!netif_running(dev))
+               return;
+
        tg3_full_lock(tp, 0);
        __tg3_set_rx_mode(dev);
        tg3_full_unlock(tp);
@@ -7174,6 +7388,9 @@ static void tg3_get_regs(struct net_device *dev,
 
        memset(p, 0, TG3_REGDUMP_LEN);
 
+       if (tp->link_config.phy_is_low_power)
+               return;
+
        tg3_full_lock(tp, 0);
 
 #define __GET_REG32(reg)       (*(p)++ = tr32(reg))
@@ -7240,6 +7457,7 @@ static int tg3_get_eeprom_len(struct net_device *dev)
 }
 
 static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val);
+static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val);
 
 static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
 {
@@ -7248,6 +7466,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        u8  *pd;
        u32 i, offset, len, val, b_offset, b_count;
 
+       if (tp->link_config.phy_is_low_power)
+               return -EAGAIN;
+
        offset = eeprom->offset;
        len = eeprom->len;
        eeprom->len = 0;
@@ -7309,6 +7530,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        u32 offset, len, b_offset, odd_len, start, end;
        u8 *buf;
 
+       if (tp->link_config.phy_is_low_power)
+               return -EAGAIN;
+
        if (eeprom->magic != TG3_EEPROM_MAGIC)
                return -EINVAL;
 
@@ -7442,6 +7666,7 @@ static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
   
        strcpy(info->driver, DRV_MODULE_NAME);
        strcpy(info->version, DRV_MODULE_VERSION);
+       strcpy(info->fw_version, tp->fw_ver);
        strcpy(info->bus_info, pci_name(tp->pdev));
 }
   
@@ -7536,11 +7761,20 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
   
        ering->rx_max_pending = TG3_RX_RING_SIZE - 1;
        ering->rx_mini_max_pending = 0;
-       ering->rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
+       if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)
+               ering->rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
+       else
+               ering->rx_jumbo_max_pending = 0;
+
+       ering->tx_max_pending = TG3_TX_RING_SIZE - 1;
 
        ering->rx_pending = tp->rx_pending;
        ering->rx_mini_pending = 0;
-       ering->rx_jumbo_pending = tp->rx_jumbo_pending;
+       if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)
+               ering->rx_jumbo_pending = tp->rx_jumbo_pending;
+       else
+               ering->rx_jumbo_pending = 0;
+
        ering->tx_pending = tp->tx_pending;
 }
   
@@ -7661,10 +7895,10 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
                return 0;
        }
   
-       if (data)
-               dev->features |= NETIF_F_IP_CSUM;
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+               ethtool_op_set_tx_hw_csum(dev, data);
        else
-               dev->features &= ~NETIF_F_IP_CSUM;
+               ethtool_op_set_tx_csum(dev, data);
 
        return 0;
 }
@@ -7734,29 +7968,52 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
 }
 
 #define NVRAM_TEST_SIZE 0x100
+#define NVRAM_SELFBOOT_FORMAT1_SIZE 0x14
 
 static int tg3_test_nvram(struct tg3 *tp)
 {
-       u32 *buf, csum;
-       int i, j, err = 0;
+       u32 *buf, csum, magic;
+       int i, j, err = 0, size;
 
-       buf = kmalloc(NVRAM_TEST_SIZE, GFP_KERNEL);
+       if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
+               return -EIO;
+
+       if (magic == TG3_EEPROM_MAGIC)
+               size = NVRAM_TEST_SIZE;
+       else if ((magic & 0xff000000) == 0xa5000000) {
+               if ((magic & 0xe00000) == 0x200000)
+                       size = NVRAM_SELFBOOT_FORMAT1_SIZE;
+               else
+                       return 0;
+       } else
+               return -EIO;
+
+       buf = kmalloc(size, GFP_KERNEL);
        if (buf == NULL)
                return -ENOMEM;
 
-       for (i = 0, j = 0; i < NVRAM_TEST_SIZE; i += 4, j++) {
+       err = -EIO;
+       for (i = 0, j = 0; i < size; i += 4, j++) {
                u32 val;
 
                if ((err = tg3_nvram_read(tp, i, &val)) != 0)
                        break;
                buf[j] = cpu_to_le32(val);
        }
-       if (i < NVRAM_TEST_SIZE)
+       if (i < size)
                goto out;
 
-       err = -EIO;
-       if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC)
-               goto out;
+       /* Selfboot format */
+       if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) {
+               u8 *buf8 = (u8 *) buf, csum8 = 0;
+
+               for (i = 0; i < size; i++)
+                       csum8 += buf8[i];
+
+               if (csum8 == 0)
+                       return 0;
+               return -EIO;
+       }
 
        /* Bootstrap checksum at offset 0x10 */
        csum = calc_crc((unsigned char *) buf, 0x10);
@@ -7802,7 +8059,7 @@ static int tg3_test_link(struct tg3 *tp)
 }
 
 /* Only test the commonly used registers */
-static const int tg3_test_registers(struct tg3 *tp)
+static int tg3_test_registers(struct tg3 *tp)
 {
        int i, is_5705;
        u32 offset, read_mask, write_mask, val, save_val, read_val;
@@ -8050,14 +8307,24 @@ static int tg3_test_memory(struct tg3 *tp)
                { 0x00008000, 0x02000},
                { 0x00010000, 0x0e000},
                { 0xffffffff, 0x00000}
+       }, mem_tbl_5755[] = {
+               { 0x00000200, 0x00008},
+               { 0x00004000, 0x00800},
+               { 0x00006000, 0x00800},
+               { 0x00008000, 0x02000},
+               { 0x00010000, 0x0c000},
+               { 0xffffffff, 0x00000}
        };
        struct mem_entry *mem_tbl;
        int err = 0;
        int i;
 
-       if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
-               mem_tbl = mem_tbl_5705;
-       else
+       if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+                       mem_tbl = mem_tbl_5755;
+               else
+                       mem_tbl = mem_tbl_5705;
+       } else
                mem_tbl = mem_tbl_570x;
 
        for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
@@ -8229,6 +8496,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
 {
        struct tg3 *tp = netdev_priv(dev);
 
+       if (tp->link_config.phy_is_low_power)
+               tg3_set_power_state(tp, PCI_D0);
+
        memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
 
        if (tg3_test_nvram(tp) != 0) {
@@ -8257,6 +8527,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                if (!err)
                        tg3_nvram_unlock(tp);
 
+               if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+                       tg3_phy_reset(tp);
+
                if (tg3_test_registers(tp) != 0) {
                        etest->flags |= ETH_TEST_FL_FAILED;
                        data[2] = 1;
@@ -8286,6 +8559,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
 
                tg3_full_unlock(tp);
        }
+       if (tp->link_config.phy_is_low_power)
+               tg3_set_power_state(tp, PCI_D3hot);
+
 }
 
 static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -8305,6 +8581,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                        break;                  /* We have no PHY */
 
+               if (tp->link_config.phy_is_low_power)
+                       return -EAGAIN;
+
                spin_lock_bh(&tp->lock);
                err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
                spin_unlock_bh(&tp->lock);
@@ -8321,6 +8600,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
 
+               if (tp->link_config.phy_is_low_power)
+                       return -EAGAIN;
+
                spin_lock_bh(&tp->lock);
                err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
                spin_unlock_bh(&tp->lock);
@@ -8464,14 +8746,14 @@ static struct ethtool_ops tg3_ethtool_ops = {
 
 static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
 {
-       u32 cursize, val;
+       u32 cursize, val, magic;
 
        tp->nvram_size = EEPROM_CHIP_SIZE;
 
-       if (tg3_nvram_read(tp, 0, &val) != 0)
+       if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
                return;
 
-       if (swab32(val) != TG3_EEPROM_MAGIC)
+       if ((magic != TG3_EEPROM_MAGIC) && ((magic & 0xff000000) != 0xa5000000))
                return;
 
        /*
@@ -8479,13 +8761,13 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
         * When we encounter our validation signature, we know the addressing
         * has wrapped around, and thus have our chip size.
         */
-       cursize = 0x800;
+       cursize = 0x10;
 
        while (cursize < tp->nvram_size) {
-               if (tg3_nvram_read(tp, cursize, &val) != 0)
+               if (tg3_nvram_read_swab(tp, cursize, &val) != 0)
                        return;
 
-               if (swab32(val) == TG3_EEPROM_MAGIC)
+               if (val == magic)
                        break;
 
                cursize <<= 1;
@@ -8498,6 +8780,15 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
 {
        u32 val;
 
+       if (tg3_nvram_read_swab(tp, 0, &val) != 0)
+               return;
+
+       /* Selfboot format */
+       if (val != TG3_EEPROM_MAGIC) {
+               tg3_get_eeprom_size(tp);
+               return;
+       }
+
        if (tg3_nvram_read(tp, 0xf0, &val) == 0) {
                if (val != 0) {
                        tp->nvram_size = (val >> 16) * 1024;
@@ -8621,6 +8912,44 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp)
        }
 }
 
+static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp)
+{
+       u32 nvcfg1;
+
+       nvcfg1 = tr32(NVRAM_CFG1);
+
+       switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
+               case FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ:
+               case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ:
+               case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ:
+               case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ:
+                       tp->nvram_jedecnum = JEDEC_ATMEL;
+                       tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+                       tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+
+                       nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+                       tw32(NVRAM_CFG1, nvcfg1);
+                       break;
+               case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED:
+               case FLASH_5755VENDOR_ATMEL_FLASH_1:
+               case FLASH_5755VENDOR_ATMEL_FLASH_2:
+               case FLASH_5755VENDOR_ATMEL_FLASH_3:
+                       tp->nvram_jedecnum = JEDEC_ATMEL;
+                       tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+                       tp->tg3_flags2 |= TG3_FLG2_FLASH;
+                       tp->nvram_pagesize = 264;
+                       break;
+               case FLASH_5752VENDOR_ST_M45PE10:
+               case FLASH_5752VENDOR_ST_M45PE20:
+               case FLASH_5752VENDOR_ST_M45PE40:
+                       tp->nvram_jedecnum = JEDEC_ST;
+                       tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+                       tp->tg3_flags2 |= TG3_FLG2_FLASH;
+                       tp->nvram_pagesize = 256;
+                       break;
+       }
+}
+
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
 static void __devinit tg3_nvram_init(struct tg3 *tp)
 {
@@ -8656,6 +8985,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
 
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
                        tg3_get_5752_nvram_info(tp);
+               else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+                       tg3_get_5787_nvram_info(tp);
                else
                        tg3_get_nvram_info(tp);
 
@@ -8725,6 +9056,34 @@ static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
        return 0;
 }
 
+static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr)
+{
+       if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
+           (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
+           (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+           (tp->nvram_jedecnum == JEDEC_ATMEL))
+
+               addr = ((addr / tp->nvram_pagesize) <<
+                       ATMEL_AT45DB0X1B_PAGE_POS) +
+                      (addr % tp->nvram_pagesize);
+
+       return addr;
+}
+
+static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr)
+{
+       if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
+           (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
+           (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+           (tp->nvram_jedecnum == JEDEC_ATMEL))
+
+               addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) *
+                       tp->nvram_pagesize) +
+                      (addr & ((1 << ATMEL_AT45DB0X1B_PAGE_POS) - 1));
+
+       return addr;
+}
+
 static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
 {
        int ret;
@@ -8737,14 +9096,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
        if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
                return tg3_nvram_read_using_eeprom(tp, offset, val);
 
-       if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
-               (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
-               (tp->nvram_jedecnum == JEDEC_ATMEL)) {
-
-               offset = ((offset / tp->nvram_pagesize) <<
-                         ATMEL_AT45DB0X1B_PAGE_POS) +
-                       (offset % tp->nvram_pagesize);
-       }
+       offset = tg3_nvram_phys_addr(tp, offset);
 
        if (offset > NVRAM_ADDR_MSK)
                return -EINVAL;
@@ -8769,6 +9121,16 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
        return ret;
 }
 
+static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val)
+{
+       int err;
+       u32 tmp;
+
+       err = tg3_nvram_read(tp, offset, &tmp);
+       *val = swab32(tmp);
+       return err;
+}
+
 static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
                                    u32 offset, u32 len, u8 *buf)
 {
@@ -8921,15 +9283,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
 
                page_off = offset % tp->nvram_pagesize;
 
-               if ((tp->tg3_flags2 & TG3_FLG2_FLASH) &&
-                       (tp->nvram_jedecnum == JEDEC_ATMEL)) {
-
-                       phy_addr = ((offset / tp->nvram_pagesize) <<
-                                   ATMEL_AT45DB0X1B_PAGE_POS) + page_off;
-               }
-               else {
-                       phy_addr = offset;
-               }
+               phy_addr = tg3_nvram_phys_addr(tp, offset);
 
                tw32(NVRAM_ADDR, phy_addr);
 
@@ -8944,6 +9298,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
                        nvram_cmd |= NVRAM_CMD_LAST;
 
                if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) &&
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
                    (tp->nvram_jedecnum == JEDEC_ST) &&
                    (nvram_cmd & NVRAM_CMD_FIRST)) {
 
@@ -9347,6 +9702,7 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
 {
        unsigned char vpd_data[256];
        int i;
+       u32 magic;
 
        if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
                /* Sun decided not to put the necessary bits in the
@@ -9356,16 +9712,43 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
                return;
        }
 
-       for (i = 0; i < 256; i += 4) {
-               u32 tmp;
+       if (tg3_nvram_read_swab(tp, 0x0, &magic))
+               return;
 
-               if (tg3_nvram_read(tp, 0x100 + i, &tmp))
-                       goto out_not_found;
+       if (magic == TG3_EEPROM_MAGIC) {
+               for (i = 0; i < 256; i += 4) {
+                       u32 tmp;
+
+                       if (tg3_nvram_read(tp, 0x100 + i, &tmp))
+                               goto out_not_found;
 
-               vpd_data[i + 0] = ((tmp >>  0) & 0xff);
-               vpd_data[i + 1] = ((tmp >>  8) & 0xff);
-               vpd_data[i + 2] = ((tmp >> 16) & 0xff);
-               vpd_data[i + 3] = ((tmp >> 24) & 0xff);
+                       vpd_data[i + 0] = ((tmp >>  0) & 0xff);
+                       vpd_data[i + 1] = ((tmp >>  8) & 0xff);
+                       vpd_data[i + 2] = ((tmp >> 16) & 0xff);
+                       vpd_data[i + 3] = ((tmp >> 24) & 0xff);
+               }
+       } else {
+               int vpd_cap;
+
+               vpd_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_VPD);
+               for (i = 0; i < 256; i += 4) {
+                       u32 tmp, j = 0;
+                       u16 tmp16;
+
+                       pci_write_config_word(tp->pdev, vpd_cap + PCI_VPD_ADDR,
+                                             i);
+                       while (j++ < 100) {
+                               pci_read_config_word(tp->pdev, vpd_cap +
+                                                    PCI_VPD_ADDR, &tmp16);
+                               if (tmp16 & 0x8000)
+                                       break;
+                               msleep(1);
+                       }
+                       pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA,
+                                             &tmp);
+                       tmp = cpu_to_le32(tmp);
+                       memcpy(&vpd_data[i], &tmp, 4);
+               }
        }
 
        /* Now parse and find the part number. */
@@ -9412,6 +9795,46 @@ out_not_found:
        strcpy(tp->board_part_number, "none");
 }
 
+static void __devinit tg3_read_fw_ver(struct tg3 *tp)
+{
+       u32 val, offset, start;
+
+       if (tg3_nvram_read_swab(tp, 0, &val))
+               return;
+
+       if (val != TG3_EEPROM_MAGIC)
+               return;
+
+       if (tg3_nvram_read_swab(tp, 0xc, &offset) ||
+           tg3_nvram_read_swab(tp, 0x4, &start))
+               return;
+
+       offset = tg3_nvram_logical_addr(tp, offset);
+       if (tg3_nvram_read_swab(tp, offset, &val))
+               return;
+
+       if ((val & 0xfc000000) == 0x0c000000) {
+               u32 ver_offset, addr;
+               int i;
+
+               if (tg3_nvram_read_swab(tp, offset + 4, &val) ||
+                   tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
+                       return;
+
+               if (val != 0)
+                       return;
+
+               addr = offset + ver_offset - start;
+               for (i = 0; i < 16; i += 4) {
+                       if (tg3_nvram_read(tp, addr + i, &val))
+                               return;
+
+                       val = cpu_to_le32(val);
+                       memcpy(tp->fw_ver + i, &val, 4);
+               }
+       }
+}
+
 #ifdef CONFIG_SPARC64
 static int __devinit tg3_is_sun_570X(struct tg3 *tp)
 {
@@ -9603,6 +10026,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
                tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
 
@@ -9610,12 +10034,18 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            (tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
                tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
 
-       if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
-               tp->tg3_flags2 |= TG3_FLG2_HW_TSO;
+       if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+                       tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
+                       tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
+               } else
+                       tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1;
+       }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752)
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787)
                tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
 
        if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
@@ -9772,7 +10202,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
 
        /* Force the chip into D0. */
-       err = tg3_set_power_state(tp, 0);
+       err = tg3_set_power_state(tp, PCI_D0);
        if (err) {
                printk(KERN_ERR PFX "(%s) transition to D0 failed\n",
                       pci_name(tp->pdev));
@@ -9825,7 +10255,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
                tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
 
-       if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+       if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
+           (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787))
                tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
 
        tp->coalesce_mode = 0;
@@ -9925,6 +10356,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        }
 
        tg3_read_partno(tp);
+       tg3_read_fw_ver(tp);
 
        if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT;
@@ -9960,10 +10392,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        else
                tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
 
-       /* It seems all chips can get confused if TX buffers
+       /* All chips before 5787 can get confused if TX buffers
         * straddle the 4GB address boundary in some cases.
         */
-       tp->dev->hard_start_xmit = tg3_start_xmit;
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+               tp->dev->hard_start_xmit = tg3_start_xmit;
+       else
+               tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug;
 
        tp->rx_offset = 2;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
@@ -10491,7 +10926,6 @@ static void __devinit tg3_init_link_config(struct tg3 *tp)
        tp->link_config.speed = SPEED_INVALID;
        tp->link_config.duplex = DUPLEX_INVALID;
        tp->link_config.autoneg = AUTONEG_ENABLE;
-       netif_carrier_off(tp->dev);
        tp->link_config.active_speed = SPEED_INVALID;
        tp->link_config.active_duplex = DUPLEX_INVALID;
        tp->link_config.phy_is_low_power = 0;
@@ -10550,6 +10984,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
        case PHY_ID_BCM5752:    return "5752";
        case PHY_ID_BCM5714:    return "5714";
        case PHY_ID_BCM5780:    return "5780";
+       case PHY_ID_BCM5787:    return "5787";
        case PHY_ID_BCM8002:    return "8002/serdes";
        case 0:                 return "serdes";
        default:                return "unknown";
@@ -10848,11 +11283,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
        }
 
-       /* TSO is off by default, user can enable using ethtool.  */
-#if 0
-       if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)
+       /* TSO is on by default on chips that support hardware TSO.
+        * Firmware TSO on older chips gives lower performance, so it
+        * is off by default, but can be enabled using ethtool.
+        */
+       if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                dev->features |= NETIF_F_TSO;
-#endif
 
 #endif
 
@@ -10896,7 +11332,11 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
         * checksumming.
         */
        if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) {
-               dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+                       dev->features |= NETIF_F_HW_CSUM;
+               else
+                       dev->features |= NETIF_F_IP_CSUM;
+               dev->features |= NETIF_F_SG;
                tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
        } else
                tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
@@ -10949,6 +11389,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
               (pdev->dma_mask == DMA_32BIT_MASK) ? 32 :
                (((u64) pdev->dma_mask == DMA_40BIT_MASK) ? 40 : 64));
 
+       netif_carrier_off(tp->dev);
+
        return 0;
 
 err_out_iounmap:
@@ -11044,7 +11486,7 @@ static int tg3_resume(struct pci_dev *pdev)
 
        pci_restore_state(tp->pdev);
 
-       err = tg3_set_power_state(tp, 0);
+       err = tg3_set_power_state(tp, PCI_D0);
        if (err)
                return err;
 
index 7e3b613..baa34c4 100644 (file)
 #define   ASIC_REV_5752                         0x06
 #define   ASIC_REV_5780                         0x08
 #define   ASIC_REV_5714                         0x09
+#define   ASIC_REV_5787                         0x0b
 #define  GET_CHIP_REV(CHIP_REV_ID)     ((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX               0x70
 #define   CHIPREV_5700_BX               0x71
 #define GRC_MDI_CTRL                   0x00006844
 #define GRC_SEEPROM_DELAY              0x00006848
 /* 0x684c --> 0x6c00 unused */
+#define GRC_FASTBOOT_PC                        0x00006894      /* 5752, 5755, 5787 */
 
 /* 0x6c00 --> 0x7000 unused */
 
 #define  FLASH_5752VENDOR_ST_M45PE10    0x02400000
 #define  FLASH_5752VENDOR_ST_M45PE20    0x02400002
 #define  FLASH_5752VENDOR_ST_M45PE40    0x02400001
+#define  FLASH_5755VENDOR_ATMEL_FLASH_1         0x03400001
+#define  FLASH_5755VENDOR_ATMEL_FLASH_2         0x03400002
+#define  FLASH_5755VENDOR_ATMEL_FLASH_3         0x03400000
+#define  FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ    0x03000003
+#define  FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ   0x03000002
+#define  FLASH_5787VENDOR_MICRO_EEPROM_64KHZ    0x03000000
+#define  FLASH_5787VENDOR_MICRO_EEPROM_376KHZ   0x02000000
 #define  NVRAM_CFG1_5752PAGE_SIZE_MASK  0x70000000
 #define  FLASH_5752PAGE_SIZE_256        0x00000000
 #define  FLASH_5752PAGE_SIZE_512        0x10000000
@@ -2185,7 +2194,7 @@ struct tg3 {
 #define TG3_FLG2_PHY_SERDES            0x00002000
 #define TG3_FLG2_CAPACITIVE_COUPLING   0x00004000
 #define TG3_FLG2_FLASH                 0x00008000
-#define TG3_FLG2_HW_TSO                        0x00010000
+#define TG3_FLG2_HW_TSO_1              0x00010000
 #define TG3_FLG2_SERDES_PREEMPHASIS    0x00020000
 #define TG3_FLG2_5705_PLUS             0x00040000
 #define TG3_FLG2_5750_PLUS             0x00080000
@@ -2198,6 +2207,9 @@ struct tg3 {
 #define TG3_FLG2_PARALLEL_DETECT       0x01000000
 #define TG3_FLG2_ICH_WORKAROUND                0x02000000
 #define TG3_FLG2_5780_CLASS            0x04000000
+#define TG3_FLG2_HW_TSO_2              0x08000000
+#define TG3_FLG2_HW_TSO                        (TG3_FLG2_HW_TSO_1 | TG3_FLG2_HW_TSO_2)
+#define TG3_FLG2_1SHOT_MSI             0x10000000
 
        u32                             split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ                3
@@ -2247,6 +2259,7 @@ struct tg3 {
 #define PHY_ID_BCM5752                 0x60008100
 #define PHY_ID_BCM5714                 0x60008340
 #define PHY_ID_BCM5780                 0x60008350
+#define PHY_ID_BCM5787                 0xbc050ce0
 #define PHY_ID_BCM8002                 0x60010140
 #define PHY_ID_INVALID                 0xffffffff
 #define PHY_ID_REV_MASK                        0x0000000f
@@ -2258,6 +2271,7 @@ struct tg3 {
        u32                             led_ctrl;
 
        char                            board_part_number[24];
+       char                            fw_ver[16];
        u32                             nic_sram_data_cfg;
        u32                             pci_clock_ctrl;
        struct pci_dev                  *pdev_peer;
@@ -2271,7 +2285,8 @@ struct tg3 {
         (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
         (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
         (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
-        (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM8002)
+        (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
+        (X) == PHY_ID_BCM8002)
 
        struct tg3_hw_stats             *hw_stats;
        dma_addr_t                      stats_mapping;
index db2c798..175ba13 100644 (file)
@@ -1495,8 +1495,7 @@ module_param(skip_pci_probe, bool, 0);
 MODULE_LICENSE("GPL");
 
 
-int
-init_module( void )
+int __init init_module( void )
 {
        struct net_device  *dev;
        int err;
index 47b5ade..2c23d75 100644 (file)
@@ -218,7 +218,7 @@ static int __init omap_cf_probe(struct device *dev)
 
        /* either CFLASH.IREQ (INT_1610_CF) or some GPIO */
        irq = platform_get_irq(pdev, 0);
-       if (!irq)
+       if (irq < 0)
                return -EINVAL;
 
        cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
index 3c606cf..5c94a5d 100644 (file)
@@ -379,6 +379,14 @@ config SCSI_AHA1740
 config SCSI_AACRAID
        tristate "Adaptec AACRAID support"
        depends on SCSI && PCI
+       help
+         This driver supports a variety of Dell, HP, Adaptec, IBM and
+         ICP storage products. For a list of supported products, refer
+         to <file:Documentation/scsi/aacraid.txt>.
+
+         To compile this driver as a module, choose M here: the module
+         will be called aacraid.
+
 
 source "drivers/scsi/aic7xxx/Kconfig.aic7xxx"
 
index 320e765..15dc2e0 100644 (file)
@@ -163,7 +163,7 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
 CFLAGS_ncr53c8xx.o     := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
 zalon7xx-objs  := zalon.o ncr53c8xx.o
 NCR_Q720_mod-objs      := NCR_Q720.o ncr53c8xx.o
-libata-objs    := libata-core.o libata-scsi.o
+libata-objs    := libata-core.o libata-scsi.o libata-bmdma.o
 oktagon_esp_mod-objs   := oktagon_esp.o oktagon_io.o
 
 # Files generated that shall be removed upon make clean
index 559ff7a..e97ab3e 100644 (file)
@@ -66,6 +66,9 @@ enum {
        AHCI_IRQ_ON_SG          = (1 << 31),
        AHCI_CMD_ATAPI          = (1 << 5),
        AHCI_CMD_WRITE          = (1 << 6),
+       AHCI_CMD_PREFETCH       = (1 << 7),
+       AHCI_CMD_RESET          = (1 << 8),
+       AHCI_CMD_CLR_BUSY       = (1 << 10),
 
        RX_FIS_D2H_REG          = 0x40, /* offset of D2H Register FIS data */
 
@@ -85,6 +88,7 @@ enum {
 
        /* HOST_CAP bits */
        HOST_CAP_64             = (1 << 31), /* PCI DAC (64-bit DMA) support */
+       HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
 
        /* registers for each SATA port */
        PORT_LST_ADDR           = 0x00, /* command list DMA addr */
@@ -138,6 +142,7 @@ enum {
        PORT_CMD_LIST_ON        = (1 << 15), /* cmd list DMA engine running */
        PORT_CMD_FIS_ON         = (1 << 14), /* FIS DMA engine running */
        PORT_CMD_FIS_RX         = (1 << 4), /* Enable FIS receive DMA engine */
+       PORT_CMD_CLO            = (1 << 3), /* Command list override */
        PORT_CMD_POWER_ON       = (1 << 2), /* Power up device */
        PORT_CMD_SPIN_UP        = (1 << 1), /* Spin up device */
        PORT_CMD_START          = (1 << 0), /* Enable port DMA engine */
@@ -184,9 +189,9 @@ struct ahci_port_priv {
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static int ahci_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static void ahci_phy_reset(struct ata_port *ap);
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void ahci_irq_clear(struct ata_port *ap);
 static void ahci_eng_timeout(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
@@ -202,11 +207,11 @@ static struct scsi_host_template ahci_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = AHCI_MAX_SG,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = AHCI_USE_CLUSTERING,
@@ -225,7 +230,7 @@ static const struct ata_port_operations ahci_ops = {
 
        .tf_read                = ahci_tf_read,
 
-       .phy_reset              = ahci_phy_reset,
+       .probe_reset            = ahci_probe_reset,
 
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
@@ -247,8 +252,7 @@ static const struct ata_port_info ahci_port_info[] = {
        {
                .sht            = &ahci_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
-                                 ATA_FLAG_PIO_DMA,
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
@@ -450,17 +454,48 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
        writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static void ahci_phy_reset(struct ata_port *ap)
+static int ahci_stop_engine(struct ata_port *ap)
 {
-       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
-       struct ata_taskfile tf;
-       struct ata_device *dev = &ap->device[0];
-       u32 new_tmp, tmp;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       int work;
+       u32 tmp;
 
-       __sata_phy_reset(ap);
+       tmp = readl(port_mmio + PORT_CMD);
+       tmp &= ~PORT_CMD_START;
+       writel(tmp, port_mmio + PORT_CMD);
 
-       if (ap->flags & ATA_FLAG_PORT_DISABLED)
-               return;
+       /* wait for engine to stop.  TODO: this could be
+        * as long as 500 msec
+        */
+       work = 1000;
+       while (work-- > 0) {
+               tmp = readl(port_mmio + PORT_CMD);
+               if ((tmp & PORT_CMD_LIST_ON) == 0)
+                       return 0;
+               udelay(10);
+       }
+
+       return -EIO;
+}
+
+static void ahci_start_engine(struct ata_port *ap)
+{
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+       u32 tmp;
+
+       tmp = readl(port_mmio + PORT_CMD);
+       tmp |= PORT_CMD_START;
+       writel(tmp, port_mmio + PORT_CMD);
+       readl(port_mmio + PORT_CMD); /* flush */
+}
+
+static unsigned int ahci_dev_classify(struct ata_port *ap)
+{
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+       struct ata_taskfile tf;
+       u32 tmp;
 
        tmp = readl(port_mmio + PORT_SIG);
        tf.lbah         = (tmp >> 24)   & 0xff;
@@ -468,15 +503,46 @@ static void ahci_phy_reset(struct ata_port *ap)
        tf.lbal         = (tmp >> 8)    & 0xff;
        tf.nsect        = (tmp)         & 0xff;
 
-       dev->class = ata_dev_classify(&tf);
-       if (!ata_dev_present(dev)) {
-               ata_port_disable(ap);
-               return;
-       }
+       return ata_dev_classify(&tf);
+}
+
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
+{
+       pp->cmd_slot[0].opts = cpu_to_le32(opts);
+       pp->cmd_slot[0].status = 0;
+       pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
+       pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+}
+
+static int ahci_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       ahci_stop_engine(ap);
+       rc = sata_std_hardreset(ap, verbose, class);
+       ahci_start_engine(ap);
+
+       if (rc == 0)
+               *class = ahci_dev_classify(ap);
+       if (*class == ATA_DEV_UNKNOWN)
+               *class = ATA_DEV_NONE;
+
+       DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+       return rc;
+}
+
+static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+{
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+       u32 new_tmp, tmp;
+
+       ata_std_postreset(ap, class);
 
        /* Make sure port's ATAPI bit is set appropriately */
        new_tmp = tmp = readl(port_mmio + PORT_CMD);
-       if (dev->class == ATA_DEV_ATAPI)
+       if (*class == ATA_DEV_ATAPI)
                new_tmp |= PORT_CMD_ATAPI;
        else
                new_tmp &= ~PORT_CMD_ATAPI;
@@ -486,6 +552,12 @@ static void ahci_phy_reset(struct ata_port *ap)
        }
 }
 
+static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+       return ata_drive_probe_reset(ap, NULL, NULL, ahci_hardreset,
+                                    ahci_postreset, classes);
+}
+
 static u8 ahci_check_status(struct ata_port *ap)
 {
        void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -533,42 +605,36 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct ahci_port_priv *pp = ap->private_data;
+       int is_atapi = is_atapi_taskfile(&qc->tf);
        u32 opts;
        const u32 cmd_fis_len = 5; /* five dwords */
        unsigned int n_elem;
 
        /*
-        * Fill in command slot information (currently only one slot,
-        * slot 0, is currently since we don't do queueing)
-        */
-
-       opts = cmd_fis_len;
-       if (qc->tf.flags & ATA_TFLAG_WRITE)
-               opts |= AHCI_CMD_WRITE;
-       if (is_atapi_taskfile(&qc->tf))
-               opts |= AHCI_CMD_ATAPI;
-
-       pp->cmd_slot[0].opts = cpu_to_le32(opts);
-       pp->cmd_slot[0].status = 0;
-       pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
-       pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
-
-       /*
         * Fill in command table information.  First, the header,
         * a SATA Register - Host to Device command FIS.
         */
        ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
-       if (opts & AHCI_CMD_ATAPI) {
+       if (is_atapi) {
                memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
-               memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, ap->cdb_len);
+               memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
+                      qc->dev->cdb_len);
        }
 
-       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
-               return;
+       n_elem = 0;
+       if (qc->flags & ATA_QCFLAG_DMAMAP)
+               n_elem = ahci_fill_sg(qc);
 
-       n_elem = ahci_fill_sg(qc);
+       /*
+        * Fill in command slot information.
+        */
+       opts = cmd_fis_len | n_elem << 16;
+       if (qc->tf.flags & ATA_TFLAG_WRITE)
+               opts |= AHCI_CMD_WRITE;
+       if (is_atapi)
+               opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
 
-       pp->cmd_slot[0].opts |= cpu_to_le32(n_elem << 16);
+       ahci_fill_cmd_slot(pp, opts);
 }
 
 static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
@@ -576,7 +642,6 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
        void __iomem *mmio = ap->host_set->mmio_base;
        void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 tmp;
-       int work;
 
        if ((ap->device[0].class != ATA_DEV_ATAPI) ||
            ((irq_stat & PORT_IRQ_TF_ERR) == 0))
@@ -592,20 +657,7 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
                        readl(port_mmio + PORT_SCR_ERR));
 
        /* stop DMA */
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp &= ~PORT_CMD_START;
-       writel(tmp, port_mmio + PORT_CMD);
-
-       /* wait for engine to stop.  TODO: this could be
-        * as long as 500 msec
-        */
-       work = 1000;
-       while (work-- > 0) {
-               tmp = readl(port_mmio + PORT_CMD);
-               if ((tmp & PORT_CMD_LIST_ON) == 0)
-                       break;
-               udelay(10);
-       }
+       ahci_stop_engine(ap);
 
        /* clear SATA phy error, if any */
        tmp = readl(port_mmio + PORT_SCR_ERR);
@@ -624,10 +676,7 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
        }
 
        /* re-start DMA */
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp |= PORT_CMD_START;
-       writel(tmp, port_mmio + PORT_CMD);
-       readl(port_mmio + PORT_CMD); /* flush */
+       ahci_start_engine(ap);
 }
 
 static void ahci_eng_timeout(struct ata_port *ap)
@@ -642,25 +691,13 @@ static void ahci_eng_timeout(struct ata_port *ap)
 
        spin_lock_irqsave(&host_set->lock, flags);
 
+       ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       if (!qc) {
-               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-                      ap->id);
-       } else {
-               ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
-
-               /* hack alert!  We cannot use the supplied completion
-                * function from inside the ->eh_strategy_handler() thread.
-                * libata is the only user of ->eh_strategy_handler() in
-                * any kernel, so the default scsi_done() assumes it is
-                * not being called from the SCSI EH.
-                */
-               qc->scsidone = scsi_finish_command;
-               qc->err_mask |= AC_ERR_OTHER;
-               ata_qc_complete(qc);
-       }
+       qc->err_mask |= AC_ERR_TIMEOUT;
 
        spin_unlock_irqrestore(&host_set->lock, flags);
+
+       ata_eh_qc_complete(qc);
 }
 
 static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
@@ -678,7 +715,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        ci = readl(port_mmio + PORT_CMD_ISSUE);
        if (likely((ci & 0x1) == 0)) {
                if (qc) {
-                       assert(qc->err_mask == 0);
+                       WARN_ON(qc->err_mask);
                        ata_qc_complete(qc);
                        qc = NULL;
                }
@@ -697,7 +734,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                ahci_restart_port(ap, status);
 
                if (qc) {
-                       qc->err_mask |= AC_ERR_OTHER;
+                       qc->err_mask |= err_mask;
                        ata_qc_complete(qc);
                }
        }
@@ -770,7 +807,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
        return IRQ_RETVAL(handled);
 }
 
-static int ahci_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
index fc3ca05..9327b62 100644 (file)
@@ -101,36 +101,54 @@ enum {
        ICH5_PCS                = 0x92, /* port control and status */
        PIIX_SCC                = 0x0A, /* sub-class code register */
 
-       PIIX_FLAG_AHCI          = (1 << 28), /* AHCI possible */
-       PIIX_FLAG_CHECKINTR     = (1 << 29), /* make sure PCI INTx enabled */
-       PIIX_FLAG_COMBINED      = (1 << 30), /* combined mode possible */
+       PIIX_FLAG_IGNORE_PCS    = (1 << 25), /* ignore PCS present bits */
+       PIIX_FLAG_SCR           = (1 << 26), /* SCR available */
+       PIIX_FLAG_AHCI          = (1 << 27), /* AHCI possible */
+       PIIX_FLAG_CHECKINTR     = (1 << 28), /* make sure PCI INTx enabled */
+       PIIX_FLAG_COMBINED      = (1 << 29), /* combined mode possible */
+       /* ICH6/7 use different scheme for map value */
+       PIIX_FLAG_COMBINED_ICH6 = PIIX_FLAG_COMBINED | (1 << 30),
 
        /* combined mode.  if set, PATA is channel 0.
         * if clear, PATA is channel 1.
         */
-       PIIX_COMB_PATA_P0       = (1 << 1),
-       PIIX_COMB               = (1 << 2), /* combined mode enabled? */
-
        PIIX_PORT_ENABLED       = (1 << 0),
        PIIX_PORT_PRESENT       = (1 << 4),
 
        PIIX_80C_PRI            = (1 << 5) | (1 << 4),
        PIIX_80C_SEC            = (1 << 7) | (1 << 6),
 
-       ich5_pata               = 0,
-       ich5_sata               = 1,
-       piix4_pata              = 2,
-       ich6_sata               = 3,
-       ich6_sata_ahci          = 4,
+       /* controller IDs */
+       piix4_pata              = 0,
+       ich5_pata               = 1,
+       ich5_sata               = 2,
+       esb_sata                = 3,
+       ich6_sata               = 4,
+       ich6_sata_ahci          = 5,
+       ich6m_sata_ahci         = 6,
+
+       /* constants for mapping table */
+       P0                      = 0,  /* port 0 */
+       P1                      = 1,  /* port 1 */
+       P2                      = 2,  /* port 2 */
+       P3                      = 3,  /* port 3 */
+       IDE                     = -1, /* IDE */
+       NA                      = -2, /* not avaliable */
+       RV                      = -3, /* reserved */
 
        PIIX_AHCI_DEVICE        = 6,
 };
 
+struct piix_map_db {
+       const u32 mask;
+       const int map[][4];
+};
+
 static int piix_init_one (struct pci_dev *pdev,
                                    const struct pci_device_id *ent);
 
-static void piix_pata_phy_reset(struct ata_port *ap);
-static void piix_sata_phy_reset(struct ata_port *ap);
+static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes);
+static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
 static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
 
@@ -147,19 +165,32 @@ static const struct pci_device_id piix_pci_tbl[] = {
         * list in drivers/pci/quirks.c.
         */
 
+       /* 82801EB (ICH5) */
        { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+       /* 82801EB (ICH5) */
        { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
-       { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
-       { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+       /* 6300ESB (ICH5 variant with broken PCS present bits) */
+       { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+       /* 6300ESB pretending RAID */
+       { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+       /* 82801FB/FW (ICH6/ICH6W) */
        { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
+       /* 82801FR/FRW (ICH6R/ICH6RW) */
        { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
-       { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+       /* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented) */
+       { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+       /* 82801GB/GR/GH (ICH7, identical to ICH6) */
        { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
-       { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+       /* 2801GBM/GHM (ICH7M, identical to ICH6M) */
+       { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+       /* Enterprise Southbridge 2 (where's the datasheet?) */
        { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+       /* SATA Controller 1 IDE (ICH8, no datasheet yet) */
        { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+       /* SATA Controller 2 IDE (ICH8, ditto) */
        { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
-       { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+       /* Mobile SATA Controller IDE (ICH8M, ditto) */
+       { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
 
        { }     /* terminate list */
 };
@@ -178,11 +209,11 @@ static struct scsi_host_template piix_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
@@ -205,7 +236,7 @@ static const struct ata_port_operations piix_pata_ops = {
        .exec_command           = ata_exec_command,
        .dev_select             = ata_std_dev_select,
 
-       .phy_reset              = piix_pata_phy_reset,
+       .probe_reset            = piix_pata_probe_reset,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -233,7 +264,7 @@ static const struct ata_port_operations piix_sata_ops = {
        .exec_command           = ata_exec_command,
        .dev_select             = ata_std_dev_select,
 
-       .phy_reset              = piix_sata_phy_reset,
+       .probe_reset            = piix_sata_probe_reset,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -252,12 +283,62 @@ static const struct ata_port_operations piix_sata_ops = {
        .host_stop              = ata_host_stop,
 };
 
+static struct piix_map_db ich5_map_db = {
+       .mask = 0x7,
+       .map = {
+               /* PM   PS   SM   SS       MAP  */
+               {  P0,  NA,  P1,  NA }, /* 000b */
+               {  P1,  NA,  P0,  NA }, /* 001b */
+               {  RV,  RV,  RV,  RV },
+               {  RV,  RV,  RV,  RV },
+               {  P0,  P1, IDE, IDE }, /* 100b */
+               {  P1,  P0, IDE, IDE }, /* 101b */
+               { IDE, IDE,  P0,  P1 }, /* 110b */
+               { IDE, IDE,  P1,  P0 }, /* 111b */
+       },
+};
+
+static struct piix_map_db ich6_map_db = {
+       .mask = 0x3,
+       .map = {
+               /* PM   PS   SM   SS       MAP */
+               {  P0,  P1,  P2,  P3 }, /* 00b */
+               { IDE, IDE,  P1,  P3 }, /* 01b */
+               {  P0,  P2, IDE, IDE }, /* 10b */
+               {  RV,  RV,  RV,  RV },
+       },
+};
+
+static struct piix_map_db ich6m_map_db = {
+       .mask = 0x3,
+       .map = {
+               /* PM   PS   SM   SS       MAP */
+               {  P0,  P1,  P2,  P3 }, /* 00b */
+               {  RV,  RV,  RV,  RV },
+               {  P0,  P2, IDE, IDE }, /* 10b */
+               {  RV,  RV,  RV,  RV },
+       },
+};
+
 static struct ata_port_info piix_port_info[] = {
+       /* piix4_pata */
+       {
+               .sht            = &piix_sht,
+               .host_flags     = ATA_FLAG_SLAVE_POSS,
+               .pio_mask       = 0x1f, /* pio0-4 */
+#if 0
+               .mwdma_mask     = 0x06, /* mwdma1-2 */
+#else
+               .mwdma_mask     = 0x00, /* mwdma broken */
+#endif
+               .udma_mask      = ATA_UDMA_MASK_40C,
+               .port_ops       = &piix_pata_ops,
+       },
+
        /* ich5_pata */
        {
                .sht            = &piix_sht,
-               .host_flags     = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
-                                 PIIX_FLAG_CHECKINTR,
+               .host_flags     = ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
                .pio_mask       = 0x1f, /* pio0-4 */
 #if 0
                .mwdma_mask     = 0x06, /* mwdma1-2 */
@@ -271,50 +352,63 @@ static struct ata_port_info piix_port_info[] = {
        /* ich5_sata */
        {
                .sht            = &piix_sht,
-               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_SRST |
-                                 PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR,
+               .host_flags     = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
+                                 PIIX_FLAG_CHECKINTR,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &piix_sata_ops,
+               .private_data   = &ich5_map_db,
        },
 
-       /* piix4_pata */
+       /* i6300esb_sata */
        {
                .sht            = &piix_sht,
-               .host_flags     = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+               .host_flags     = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
+                                 PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
                .pio_mask       = 0x1f, /* pio0-4 */
-#if 0
-               .mwdma_mask     = 0x06, /* mwdma1-2 */
-#else
-               .mwdma_mask     = 0x00, /* mwdma broken */
-#endif
-               .udma_mask      = ATA_UDMA_MASK_40C,
-               .port_ops       = &piix_pata_ops,
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = 0x7f, /* udma0-6 */
+               .port_ops       = &piix_sata_ops,
+               .private_data   = &ich5_map_db,
        },
 
        /* ich6_sata */
        {
                .sht            = &piix_sht,
-               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_SRST |
-                                 PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
-                                 ATA_FLAG_SLAVE_POSS,
+               .host_flags     = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+                                 PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &piix_sata_ops,
+               .private_data   = &ich6_map_db,
        },
 
        /* ich6_sata_ahci */
        {
                .sht            = &piix_sht,
-               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_SRST |
-                                 PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
-                                 ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+               .host_flags     = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+                                 PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+                                 PIIX_FLAG_AHCI,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = 0x7f, /* udma0-6 */
+               .port_ops       = &piix_sata_ops,
+               .private_data   = &ich6_map_db,
+       },
+
+       /* ich6m_sata_ahci */
+       {
+               .sht            = &piix_sht,
+               .host_flags     = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+                                 PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+                                 PIIX_FLAG_AHCI,
                .pio_mask       = 0x1f, /* pio0-4 */
                .mwdma_mask     = 0x07, /* mwdma0-2 */
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &piix_sata_ops,
+               .private_data   = &ich6m_map_db,
        },
 };
 
@@ -363,102 +457,123 @@ cbl40:
 }
 
 /**
- *     piix_pata_phy_reset - Probe specified port on PATA host controller
- *     @ap: Port to probe
+ *     piix_pata_probeinit - probeinit for PATA host controller
+ *     @ap: Target port
  *
- *     Probe PATA phy.
+ *     Probeinit including cable detection.
  *
  *     LOCKING:
  *     None (inherited from caller).
  */
+static void piix_pata_probeinit(struct ata_port *ap)
+{
+       piix_pata_cbl_detect(ap);
+       ata_std_probeinit(ap);
+}
 
-static void piix_pata_phy_reset(struct ata_port *ap)
+/**
+ *     piix_pata_probe_reset - Perform reset on PATA port and classify
+ *     @ap: Port to reset
+ *     @classes: Resulting classes of attached devices
+ *
+ *     Reset PATA phy and classify attached devices.
+ *
+ *     LOCKING:
+ *     None (inherited from caller).
+ */
+static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
 
        if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
-               ata_port_disable(ap);
                printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
-               return;
+               return 0;
        }
 
-       piix_pata_cbl_detect(ap);
-
-       ata_port_probe(ap);
-
-       ata_bus_reset(ap);
+       return ata_drive_probe_reset(ap, piix_pata_probeinit,
+                                    ata_std_softreset, NULL,
+                                    ata_std_postreset, classes);
 }
 
 /**
  *     piix_sata_probe - Probe PCI device for present SATA devices
  *     @ap: Port associated with the PCI device we wish to probe
  *
- *     Reads SATA PCI device's PCI config register Port Configuration
- *     and Status (PCS) to determine port and device availability.
+ *     Reads and configures SATA PCI device's PCI config register
+ *     Port Configuration and Status (PCS) to determine port and
+ *     device availability.
  *
  *     LOCKING:
  *     None (inherited from caller).
  *
  *     RETURNS:
- *     Non-zero if port is enabled, it may or may not have a device
- *     attached in that case (PRESENT bit would only be set if BIOS probe
- *     was done). Zero is returned if port is disabled.
+ *     Mask of avaliable devices on the port.
  */
-static int piix_sata_probe (struct ata_port *ap)
+static unsigned int piix_sata_probe (struct ata_port *ap)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-       int combined = (ap->flags & ATA_FLAG_SLAVE_POSS);
-       int orig_mask, mask, i;
+       const unsigned int *map = ap->host_set->private_data;
+       int base = 2 * ap->hard_port_no;
+       unsigned int present_mask = 0;
+       int port, i;
        u8 pcs;
 
-       mask = (PIIX_PORT_PRESENT << ap->hard_port_no) |
-              (PIIX_PORT_ENABLED << ap->hard_port_no);
-
        pci_read_config_byte(pdev, ICH5_PCS, &pcs);
-       orig_mask = (int) pcs & 0xff;
-
-       /* TODO: this is vaguely wrong for ICH6 combined mode,
-        * where only two of the four SATA ports are mapped
-        * onto a single ATA channel.  It is also vaguely inaccurate
-        * for ICH5, which has only two ports.  However, this is ok,
-        * as further device presence detection code will handle
-        * any false positives produced here.
-        */
+       DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
 
-       for (i = 0; i < 4; i++) {
-               mask = (PIIX_PORT_ENABLED << i);
+       /* enable all ports on this ap and wait for them to settle */
+       for (i = 0; i < 2; i++) {
+               port = map[base + i];
+               if (port >= 0)
+                       pcs |= 1 << port;
+       }
+
+       pci_write_config_byte(pdev, ICH5_PCS, pcs);
+       msleep(100);
 
-               if ((orig_mask & mask) == mask)
-                       if (combined || (i == ap->hard_port_no))
-                               return 1;
+       /* let's see which devices are present */
+       pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+
+       for (i = 0; i < 2; i++) {
+               port = map[base + i];
+               if (port < 0)
+                       continue;
+               if (ap->flags & PIIX_FLAG_IGNORE_PCS || pcs & 1 << (4 + port))
+                       present_mask |= 1 << i;
+               else
+                       pcs &= ~(1 << port);
        }
 
-       return 0;
+       /* disable offline ports on non-AHCI controllers */
+       if (!(ap->flags & PIIX_FLAG_AHCI))
+               pci_write_config_byte(pdev, ICH5_PCS, pcs);
+
+       DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
+               ap->id, pcs, present_mask);
+
+       return present_mask;
 }
 
 /**
- *     piix_sata_phy_reset - Probe specified port on SATA host controller
- *     @ap: Port to probe
+ *     piix_sata_probe_reset - Perform reset on SATA port and classify
+ *     @ap: Port to reset
+ *     @classes: Resulting classes of attached devices
  *
- *     Probe SATA phy.
+ *     Reset SATA phy and classify attached devices.
  *
  *     LOCKING:
  *     None (inherited from caller).
  */
-
-static void piix_sata_phy_reset(struct ata_port *ap)
+static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes)
 {
        if (!piix_sata_probe(ap)) {
-               ata_port_disable(ap);
                printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
-               return;
+               return 0;
        }
 
-       ap->cbl = ATA_CBL_SATA;
-
-       ata_port_probe(ap);
-
-       ata_bus_reset(ap);
+       return ata_drive_probe_reset(ap, ata_std_probeinit,
+                                    ata_std_softreset, NULL,
+                                    ata_std_postreset, classes);
 }
 
 /**
@@ -627,6 +742,7 @@ static int piix_disable_ahci(struct pci_dev *pdev)
 
 /**
  *     piix_check_450nx_errata -       Check for problem 450NX setup
+ *     @ata_dev: the PCI device to check
  *     
  *     Check for the present of 450NX errata #19 and errata #25. If
  *     they are found return an error code so we can turn off DMA
@@ -659,6 +775,54 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
        return no_piix_dma;
 }              
 
+static void __devinit piix_init_sata_map(struct pci_dev *pdev,
+                                        struct ata_port_info *pinfo)
+{
+       struct piix_map_db *map_db = pinfo[0].private_data;
+       const unsigned int *map;
+       int i, invalid_map = 0;
+       u8 map_value;
+
+       pci_read_config_byte(pdev, ICH5_PMR, &map_value);
+
+       map = map_db->map[map_value & map_db->mask];
+
+       dev_printk(KERN_INFO, &pdev->dev, "MAP [");
+       for (i = 0; i < 4; i++) {
+               switch (map[i]) {
+               case RV:
+                       invalid_map = 1;
+                       printk(" XX");
+                       break;
+
+               case NA:
+                       printk(" --");
+                       break;
+
+               case IDE:
+                       WARN_ON((i & 1) || map[i + 1] != IDE);
+                       pinfo[i / 2] = piix_port_info[ich5_pata];
+                       i++;
+                       printk(" IDE IDE");
+                       break;
+
+               default:
+                       printk(" P%d", map[i]);
+                       if (i & 1)
+                               pinfo[i / 2].host_flags |= ATA_FLAG_SLAVE_POSS;
+                       break;
+               }
+       }
+       printk(" ]\n");
+
+       if (invalid_map)
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "invalid MAP value %u\n", map_value);
+
+       pinfo[0].private_data = (void *)map;
+       pinfo[1].private_data = (void *)map;
+}
+
 /**
  *     piix_init_one - Register PIIX ATA PCI device with kernel services
  *     @pdev: PCI device to register
@@ -677,9 +841,9 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
 static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
-       struct ata_port_info *port_info[2];
-       unsigned int combined = 0;
-       unsigned int pata_chan = 0, sata_chan = 0;
+       struct ata_port_info port_info[2];
+       struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
+       unsigned long host_flags;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev,
@@ -689,10 +853,12 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!in_module_init)
                return -ENODEV;
 
-       port_info[0] = &piix_port_info[ent->driver_data];
-       port_info[1] = &piix_port_info[ent->driver_data];
+       port_info[0] = piix_port_info[ent->driver_data];
+       port_info[1] = piix_port_info[ent->driver_data];
+
+       host_flags = port_info[0].host_flags;
 
-       if (port_info[0]->host_flags & PIIX_FLAG_AHCI) {
+       if (host_flags & PIIX_FLAG_AHCI) {
                u8 tmp;
                pci_read_config_byte(pdev, PIIX_SCC, &tmp);
                if (tmp == PIIX_AHCI_DEVICE) {
@@ -702,18 +868,9 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {
-               u8 tmp;
-               pci_read_config_byte(pdev, ICH5_PMR, &tmp);
-
-               if (tmp & PIIX_COMB) {
-                       combined = 1;
-                       if (tmp & PIIX_COMB_PATA_P0)
-                               sata_chan = 1;
-                       else
-                               pata_chan = 1;
-               }
-       }
+       /* Initialize SATA map */
+       if (host_flags & ATA_FLAG_SATA)
+               piix_init_sata_map(pdev, port_info);
 
        /* On ICH5, some BIOSen disable the interrupt using the
         * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
@@ -721,28 +878,19 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
         * MSI is disabled (and it is disabled, as we don't use
         * message-signalled interrupts currently).
         */
-       if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR)
+       if (host_flags & PIIX_FLAG_CHECKINTR)
                pci_intx(pdev, 1);
 
-       if (combined) {
-               port_info[sata_chan] = &piix_port_info[ent->driver_data];
-               port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS;
-               port_info[pata_chan] = &piix_port_info[ich5_pata];
-
-               dev_printk(KERN_WARNING, &pdev->dev,
-                          "combined mode detected (p=%u, s=%u)\n",
-                          pata_chan, sata_chan);
-       }
        if (piix_check_450nx_errata(pdev)) {
                /* This writes into the master table but it does not
                   really matter for this errata as we will apply it to
                   all the PIIX devices on the board */
-               port_info[0]->mwdma_mask = 0;
-               port_info[0]->udma_mask = 0;
-               port_info[1]->mwdma_mask = 0;
-               port_info[1]->udma_mask = 0;
+               port_info[0].mwdma_mask = 0;
+               port_info[0].udma_mask = 0;
+               port_info[1].mwdma_mask = 0;
+               port_info[1].udma_mask = 0;
        }
-       return ata_pci_init_one(pdev, port_info, 2);
+       return ata_pci_init_one(pdev, ppinfo, 2);
 }
 
 static int __init piix_init(void)
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
new file mode 100644 (file)
index 0000000..a93336a
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ *  libata-bmdma.c - helper library for PCI IDE BMDMA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *                 Please ALWAYS copy linux-ide@vger.kernel.org
+ *                 on emails.
+ *
+ *  Copyright 2003-2006 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2006 Jeff Garzik
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available from http://www.t13.org/ and
+ *  http://www.sata-io.org/
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/libata.h>
+
+#include "libata.h"
+
+/**
+ *     ata_tf_load_pio - send taskfile registers to host controller
+ *     @ap: Port to which output is sent
+ *     @tf: ATA taskfile register set
+ *
+ *     Outputs ATA taskfile to standard ATA host controller.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+       struct ata_ioports *ioaddr = &ap->ioaddr;
+       unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+       if (tf->ctl != ap->last_ctl) {
+               outb(tf->ctl, ioaddr->ctl_addr);
+               ap->last_ctl = tf->ctl;
+               ata_wait_idle(ap);
+       }
+
+       if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+               outb(tf->hob_feature, ioaddr->feature_addr);
+               outb(tf->hob_nsect, ioaddr->nsect_addr);
+               outb(tf->hob_lbal, ioaddr->lbal_addr);
+               outb(tf->hob_lbam, ioaddr->lbam_addr);
+               outb(tf->hob_lbah, ioaddr->lbah_addr);
+               VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+                       tf->hob_feature,
+                       tf->hob_nsect,
+                       tf->hob_lbal,
+                       tf->hob_lbam,
+                       tf->hob_lbah);
+       }
+
+       if (is_addr) {
+               outb(tf->feature, ioaddr->feature_addr);
+               outb(tf->nsect, ioaddr->nsect_addr);
+               outb(tf->lbal, ioaddr->lbal_addr);
+               outb(tf->lbam, ioaddr->lbam_addr);
+               outb(tf->lbah, ioaddr->lbah_addr);
+               VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+                       tf->feature,
+                       tf->nsect,
+                       tf->lbal,
+                       tf->lbam,
+                       tf->lbah);
+       }
+
+       if (tf->flags & ATA_TFLAG_DEVICE) {
+               outb(tf->device, ioaddr->device_addr);
+               VPRINTK("device 0x%X\n", tf->device);
+       }
+
+       ata_wait_idle(ap);
+}
+
+/**
+ *     ata_tf_load_mmio - send taskfile registers to host controller
+ *     @ap: Port to which output is sent
+ *     @tf: ATA taskfile register set
+ *
+ *     Outputs ATA taskfile to standard ATA host controller using MMIO.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+       struct ata_ioports *ioaddr = &ap->ioaddr;
+       unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+       if (tf->ctl != ap->last_ctl) {
+               writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+               ap->last_ctl = tf->ctl;
+               ata_wait_idle(ap);
+       }
+
+       if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+               writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
+               writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
+               writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
+               writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
+               writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
+               VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+                       tf->hob_feature,
+                       tf->hob_nsect,
+                       tf->hob_lbal,
+                       tf->hob_lbam,
+                       tf->hob_lbah);
+       }
+
+       if (is_addr) {
+               writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
+               writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
+               writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
+               writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
+               writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+               VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+                       tf->feature,
+                       tf->nsect,
+                       tf->lbal,
+                       tf->lbam,
+                       tf->lbah);
+       }
+
+       if (tf->flags & ATA_TFLAG_DEVICE) {
+               writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+               VPRINTK("device 0x%X\n", tf->device);
+       }
+
+       ata_wait_idle(ap);
+}
+
+
+/**
+ *     ata_tf_load - send taskfile registers to host controller
+ *     @ap: Port to which output is sent
+ *     @tf: ATA taskfile register set
+ *
+ *     Outputs ATA taskfile to standard ATA host controller using MMIO
+ *     or PIO as indicated by the ATA_FLAG_MMIO flag.
+ *     Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ *     Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ *     hob_lbal, hob_lbam, and hob_lbah.
+ *
+ *     This function waits for idle (!BUSY and !DRQ) after writing
+ *     registers.  If the control register has a new value, this
+ *     function also waits for idle after writing control and before
+ *     writing the remaining registers.
+ *
+ *     May be used as the tf_load() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+       if (ap->flags & ATA_FLAG_MMIO)
+               ata_tf_load_mmio(ap, tf);
+       else
+               ata_tf_load_pio(ap, tf);
+}
+
+/**
+ *     ata_exec_command_pio - issue ATA command to host controller
+ *     @ap: port to which command is being issued
+ *     @tf: ATA taskfile register set
+ *
+ *     Issues PIO write to ATA command register, with proper
+ *     synchronization with interrupt handler / other threads.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+       DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+               outb(tf->command, ap->ioaddr.command_addr);
+       ata_pause(ap);
+}
+
+
+/**
+ *     ata_exec_command_mmio - issue ATA command to host controller
+ *     @ap: port to which command is being issued
+ *     @tf: ATA taskfile register set
+ *
+ *     Issues MMIO write to ATA command register, with proper
+ *     synchronization with interrupt handler / other threads.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+       DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+               writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
+       ata_pause(ap);
+}
+
+
+/**
+ *     ata_exec_command - issue ATA command to host controller
+ *     @ap: port to which command is being issued
+ *     @tf: ATA taskfile register set
+ *
+ *     Issues PIO/MMIO write to ATA command register, with proper
+ *     synchronization with interrupt handler / other threads.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+       if (ap->flags & ATA_FLAG_MMIO)
+               ata_exec_command_mmio(ap, tf);
+       else
+               ata_exec_command_pio(ap, tf);
+}
+
+/**
+ *     ata_tf_read_pio - input device's ATA taskfile shadow registers
+ *     @ap: Port from which input is read
+ *     @tf: ATA taskfile register set for storing input
+ *
+ *     Reads ATA taskfile registers for currently-selected device
+ *     into @tf.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       struct ata_ioports *ioaddr = &ap->ioaddr;
+
+       tf->command = ata_check_status(ap);
+       tf->feature = inb(ioaddr->error_addr);
+       tf->nsect = inb(ioaddr->nsect_addr);
+       tf->lbal = inb(ioaddr->lbal_addr);
+       tf->lbam = inb(ioaddr->lbam_addr);
+       tf->lbah = inb(ioaddr->lbah_addr);
+       tf->device = inb(ioaddr->device_addr);
+
+       if (tf->flags & ATA_TFLAG_LBA48) {
+               outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+               tf->hob_feature = inb(ioaddr->error_addr);
+               tf->hob_nsect = inb(ioaddr->nsect_addr);
+               tf->hob_lbal = inb(ioaddr->lbal_addr);
+               tf->hob_lbam = inb(ioaddr->lbam_addr);
+               tf->hob_lbah = inb(ioaddr->lbah_addr);
+       }
+}
+
+/**
+ *     ata_tf_read_mmio - input device's ATA taskfile shadow registers
+ *     @ap: Port from which input is read
+ *     @tf: ATA taskfile register set for storing input
+ *
+ *     Reads ATA taskfile registers for currently-selected device
+ *     into @tf via MMIO.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       struct ata_ioports *ioaddr = &ap->ioaddr;
+
+       tf->command = ata_check_status(ap);
+       tf->feature = readb((void __iomem *)ioaddr->error_addr);
+       tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
+       tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
+       tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
+       tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
+       tf->device = readb((void __iomem *)ioaddr->device_addr);
+
+       if (tf->flags & ATA_TFLAG_LBA48) {
+               writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
+               tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
+               tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
+               tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
+               tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
+               tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
+       }
+}
+
+
+/**
+ *     ata_tf_read - input device's ATA taskfile shadow registers
+ *     @ap: Port from which input is read
+ *     @tf: ATA taskfile register set for storing input
+ *
+ *     Reads ATA taskfile registers for currently-selected device
+ *     into @tf.
+ *
+ *     Reads nsect, lbal, lbam, lbah, and device.  If ATA_TFLAG_LBA48
+ *     is set, also reads the hob registers.
+ *
+ *     May be used as the tf_read() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+       if (ap->flags & ATA_FLAG_MMIO)
+               ata_tf_read_mmio(ap, tf);
+       else
+               ata_tf_read_pio(ap, tf);
+}
+
+/**
+ *     ata_check_status_pio - Read device status reg & clear interrupt
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile status register for currently-selected device
+ *     and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static u8 ata_check_status_pio(struct ata_port *ap)
+{
+       return inb(ap->ioaddr.status_addr);
+}
+
+/**
+ *     ata_check_status_mmio - Read device status reg & clear interrupt
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile status register for currently-selected device
+ *     via MMIO and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static u8 ata_check_status_mmio(struct ata_port *ap)
+{
+               return readb((void __iomem *) ap->ioaddr.status_addr);
+}
+
+
+/**
+ *     ata_check_status - Read device status reg & clear interrupt
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile status register for currently-selected device
+ *     and return its value. This also clears pending interrupts
+ *      from this device
+ *
+ *     May be used as the check_status() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+u8 ata_check_status(struct ata_port *ap)
+{
+       if (ap->flags & ATA_FLAG_MMIO)
+               return ata_check_status_mmio(ap);
+       return ata_check_status_pio(ap);
+}
+
+
+/**
+ *     ata_altstatus - Read device alternate status reg
+ *     @ap: port where the device is
+ *
+ *     Reads ATA taskfile alternate status register for
+ *     currently-selected device and return its value.
+ *
+ *     Note: may NOT be used as the check_altstatus() entry in
+ *     ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+u8 ata_altstatus(struct ata_port *ap)
+{
+       if (ap->ops->check_altstatus)
+               return ap->ops->check_altstatus(ap);
+
+       if (ap->flags & ATA_FLAG_MMIO)
+               return readb((void __iomem *)ap->ioaddr.altstatus_addr);
+       return inb(ap->ioaddr.altstatus_addr);
+}
+
+#ifdef CONFIG_PCI
+static struct ata_probe_ent *
+ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
+{
+       struct ata_probe_ent *probe_ent;
+
+       probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+       if (!probe_ent) {
+               printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+                      kobject_name(&(dev->kobj)));
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&probe_ent->node);
+       probe_ent->dev = dev;
+
+       probe_ent->sht = port->sht;
+       probe_ent->host_flags = port->host_flags;
+       probe_ent->pio_mask = port->pio_mask;
+       probe_ent->mwdma_mask = port->mwdma_mask;
+       probe_ent->udma_mask = port->udma_mask;
+       probe_ent->port_ops = port->port_ops;
+
+       return probe_ent;
+}
+
+
+/**
+ *     ata_pci_init_native_mode - Initialize native-mode driver
+ *     @pdev:  pci device to be initialized
+ *     @port:  array[2] of pointers to port info structures.
+ *     @ports: bitmap of ports present
+ *
+ *     Utility function which allocates and initializes an
+ *     ata_probe_ent structure for a standard dual-port
+ *     PIO-based IDE controller.  The returned ata_probe_ent
+ *     structure can be passed to ata_device_add().  The returned
+ *     ata_probe_ent structure should then be freed with kfree().
+ *
+ *     The caller need only pass the address of the primary port, the
+ *     secondary will be deduced automatically. If the device has non
+ *     standard secondary port mappings this function can be called twice,
+ *     once for each interface.
+ */
+
+struct ata_probe_ent *
+ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
+{
+       struct ata_probe_ent *probe_ent =
+               ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+       int p = 0;
+
+       if (!probe_ent)
+               return NULL;
+
+       probe_ent->irq = pdev->irq;
+       probe_ent->irq_flags = SA_SHIRQ;
+       probe_ent->private_data = port[0]->private_data;
+
+       if (ports & ATA_PORT_PRIMARY) {
+               probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
+               probe_ent->port[p].altstatus_addr =
+               probe_ent->port[p].ctl_addr =
+                       pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+               probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
+               ata_std_ports(&probe_ent->port[p]);
+               p++;
+       }
+
+       if (ports & ATA_PORT_SECONDARY) {
+               probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
+               probe_ent->port[p].altstatus_addr =
+               probe_ent->port[p].ctl_addr =
+                       pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+               probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+               ata_std_ports(&probe_ent->port[p]);
+               p++;
+       }
+
+       probe_ent->n_ports = p;
+       return probe_ent;
+}
+
+
+static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
+                               struct ata_port_info *port, int port_num)
+{
+       struct ata_probe_ent *probe_ent;
+
+       probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
+       if (!probe_ent)
+               return NULL;
+
+       probe_ent->legacy_mode = 1;
+       probe_ent->n_ports = 1;
+       probe_ent->hard_port_no = port_num;
+       probe_ent->private_data = port->private_data;
+
+       switch(port_num)
+       {
+               case 0:
+                       probe_ent->irq = 14;
+                       probe_ent->port[0].cmd_addr = 0x1f0;
+                       probe_ent->port[0].altstatus_addr =
+                       probe_ent->port[0].ctl_addr = 0x3f6;
+                       break;
+               case 1:
+                       probe_ent->irq = 15;
+                       probe_ent->port[0].cmd_addr = 0x170;
+                       probe_ent->port[0].altstatus_addr =
+                       probe_ent->port[0].ctl_addr = 0x376;
+                       break;
+       }
+
+       probe_ent->port[0].bmdma_addr =
+               pci_resource_start(pdev, 4) + 8 * port_num;
+       ata_std_ports(&probe_ent->port[0]);
+
+       return probe_ent;
+}
+
+
+/**
+ *     ata_pci_init_one - Initialize/register PCI IDE host controller
+ *     @pdev: Controller to be initialized
+ *     @port_info: Information from low-level host driver
+ *     @n_ports: Number of ports attached to host controller
+ *
+ *     This is a helper function which can be called from a driver's
+ *     xxx_init_one() probe function if the hardware uses traditional
+ *     IDE taskfile registers.
+ *
+ *     This function calls pci_enable_device(), reserves its register
+ *     regions, sets the dma mask, enables bus master mode, and calls
+ *     ata_device_add()
+ *
+ *     LOCKING:
+ *     Inherited from PCI layer (may sleep).
+ *
+ *     RETURNS:
+ *     Zero on success, negative on errno-based value on error.
+ */
+
+int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+                     unsigned int n_ports)
+{
+       struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
+       struct ata_port_info *port[2];
+       u8 tmp8, mask;
+       unsigned int legacy_mode = 0;
+       int disable_dev_on_err = 1;
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       port[0] = port_info[0];
+       if (n_ports > 1)
+               port[1] = port_info[1];
+       else
+               port[1] = port[0];
+
+       if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
+           && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+               /* TODO: What if one channel is in native mode ... */
+               pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+               mask = (1 << 2) | (1 << 0);
+               if ((tmp8 & mask) != mask)
+                       legacy_mode = (1 << 3);
+       }
+
+       /* FIXME... */
+       if ((!legacy_mode) && (n_ports > 2)) {
+               printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
+               n_ports = 2;
+               /* For now */
+       }
+
+       /* FIXME: Really for ATA it isn't safe because the device may be
+          multi-purpose and we want to leave it alone if it was already
+          enabled. Secondly for shared use as Arjan says we want refcounting
+
+          Checking dev->is_enabled is insufficient as this is not set at
+          boot for the primary video which is BIOS enabled
+         */
+
+       rc = pci_enable_device(pdev);
+       if (rc)
+               return rc;
+
+       rc = pci_request_regions(pdev, DRV_NAME);
+       if (rc) {
+               disable_dev_on_err = 0;
+               goto err_out;
+       }
+
+       /* FIXME: Should use platform specific mappers for legacy port ranges */
+       if (legacy_mode) {
+               if (!request_region(0x1f0, 8, "libata")) {
+                       struct resource *conflict, res;
+                       res.start = 0x1f0;
+                       res.end = 0x1f0 + 8 - 1;
+                       conflict = ____request_resource(&ioport_resource, &res);
+                       if (!strcmp(conflict->name, "libata"))
+                               legacy_mode |= (1 << 0);
+                       else {
+                               disable_dev_on_err = 0;
+                               printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+                       }
+               } else
+                       legacy_mode |= (1 << 0);
+
+               if (!request_region(0x170, 8, "libata")) {
+                       struct resource *conflict, res;
+                       res.start = 0x170;
+                       res.end = 0x170 + 8 - 1;
+                       conflict = ____request_resource(&ioport_resource, &res);
+                       if (!strcmp(conflict->name, "libata"))
+                               legacy_mode |= (1 << 1);
+                       else {
+                               disable_dev_on_err = 0;
+                               printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+                       }
+               } else
+                       legacy_mode |= (1 << 1);
+       }
+
+       /* we have legacy mode, but all ports are unavailable */
+       if (legacy_mode == (1 << 3)) {
+               rc = -EBUSY;
+               goto err_out_regions;
+       }
+
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               goto err_out_regions;
+       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+               goto err_out_regions;
+
+       if (legacy_mode) {
+               if (legacy_mode & (1 << 0))
+                       probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
+               if (legacy_mode & (1 << 1))
+                       probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
+       } else {
+               if (n_ports == 2)
+                       probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+               else
+                       probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
+       }
+       if (!probe_ent && !probe_ent2) {
+               rc = -ENOMEM;
+               goto err_out_regions;
+       }
+
+       pci_set_master(pdev);
+
+       /* FIXME: check ata_device_add return */
+       if (legacy_mode) {
+               if (legacy_mode & (1 << 0))
+                       ata_device_add(probe_ent);
+               if (legacy_mode & (1 << 1))
+                       ata_device_add(probe_ent2);
+       } else
+               ata_device_add(probe_ent);
+
+       kfree(probe_ent);
+       kfree(probe_ent2);
+
+       return 0;
+
+err_out_regions:
+       if (legacy_mode & (1 << 0))
+               release_region(0x1f0, 8);
+       if (legacy_mode & (1 << 1))
+               release_region(0x170, 8);
+       pci_release_regions(pdev);
+err_out:
+       if (disable_dev_on_err)
+               pci_disable_device(pdev);
+       return rc;
+}
+
+#endif /* CONFIG_PCI */
+
index 4f91b0d..714b42b 100644 (file)
 
 #include "libata.h"
 
-static unsigned int ata_busy_sleep (struct ata_port *ap,
-                                   unsigned long tmout_pat,
-                                   unsigned long tmout);
-static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev);
-static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev);
+static unsigned int ata_dev_init_params(struct ata_port *ap,
+                                       struct ata_device *dev);
 static void ata_set_mode(struct ata_port *ap);
 static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev);
-static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift);
-static int fgb(u32 bitmap);
-static int ata_choose_xfer_mode(const struct ata_port *ap,
-                               u8 *xfer_mode_out,
-                               unsigned int *xfer_shift_out);
-static void __ata_qc_complete(struct ata_queued_cmd *qc);
+static unsigned int ata_dev_xfermask(struct ata_port *ap,
+                                    struct ata_device *dev);
 
 static unsigned int ata_unique_id = 1;
 static struct workqueue_struct *ata_wq;
 
-int atapi_enabled = 0;
+int atapi_enabled = 1;
 module_param(atapi_enabled, int, 0444);
 MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
 
@@ -91,403 +84,6 @@ MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
-/**
- *     ata_tf_load_pio - send taskfile registers to host controller
- *     @ap: Port to which output is sent
- *     @tf: ATA taskfile register set
- *
- *     Outputs ATA taskfile to standard ATA host controller.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-
-static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-       unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
-       if (tf->ctl != ap->last_ctl) {
-               outb(tf->ctl, ioaddr->ctl_addr);
-               ap->last_ctl = tf->ctl;
-               ata_wait_idle(ap);
-       }
-
-       if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-               outb(tf->hob_feature, ioaddr->feature_addr);
-               outb(tf->hob_nsect, ioaddr->nsect_addr);
-               outb(tf->hob_lbal, ioaddr->lbal_addr);
-               outb(tf->hob_lbam, ioaddr->lbam_addr);
-               outb(tf->hob_lbah, ioaddr->lbah_addr);
-               VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
-                       tf->hob_feature,
-                       tf->hob_nsect,
-                       tf->hob_lbal,
-                       tf->hob_lbam,
-                       tf->hob_lbah);
-       }
-
-       if (is_addr) {
-               outb(tf->feature, ioaddr->feature_addr);
-               outb(tf->nsect, ioaddr->nsect_addr);
-               outb(tf->lbal, ioaddr->lbal_addr);
-               outb(tf->lbam, ioaddr->lbam_addr);
-               outb(tf->lbah, ioaddr->lbah_addr);
-               VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
-                       tf->feature,
-                       tf->nsect,
-                       tf->lbal,
-                       tf->lbam,
-                       tf->lbah);
-       }
-
-       if (tf->flags & ATA_TFLAG_DEVICE) {
-               outb(tf->device, ioaddr->device_addr);
-               VPRINTK("device 0x%X\n", tf->device);
-       }
-
-       ata_wait_idle(ap);
-}
-
-/**
- *     ata_tf_load_mmio - send taskfile registers to host controller
- *     @ap: Port to which output is sent
- *     @tf: ATA taskfile register set
- *
- *     Outputs ATA taskfile to standard ATA host controller using MMIO.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-
-static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-       unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
-       if (tf->ctl != ap->last_ctl) {
-               writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
-               ap->last_ctl = tf->ctl;
-               ata_wait_idle(ap);
-       }
-
-       if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-               writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
-               writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
-               writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
-               writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
-               writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
-               VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
-                       tf->hob_feature,
-                       tf->hob_nsect,
-                       tf->hob_lbal,
-                       tf->hob_lbam,
-                       tf->hob_lbah);
-       }
-
-       if (is_addr) {
-               writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
-               writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
-               writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
-               writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
-               writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
-               VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
-                       tf->feature,
-                       tf->nsect,
-                       tf->lbal,
-                       tf->lbam,
-                       tf->lbah);
-       }
-
-       if (tf->flags & ATA_TFLAG_DEVICE) {
-               writeb(tf->device, (void __iomem *) ioaddr->device_addr);
-               VPRINTK("device 0x%X\n", tf->device);
-       }
-
-       ata_wait_idle(ap);
-}
-
-
-/**
- *     ata_tf_load - send taskfile registers to host controller
- *     @ap: Port to which output is sent
- *     @tf: ATA taskfile register set
- *
- *     Outputs ATA taskfile to standard ATA host controller using MMIO
- *     or PIO as indicated by the ATA_FLAG_MMIO flag.
- *     Writes the control, feature, nsect, lbal, lbam, and lbah registers.
- *     Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
- *     hob_lbal, hob_lbam, and hob_lbah.
- *
- *     This function waits for idle (!BUSY and !DRQ) after writing
- *     registers.  If the control register has a new value, this
- *     function also waits for idle after writing control and before
- *     writing the remaining registers.
- *
- *     May be used as the tf_load() entry in ata_port_operations.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       if (ap->flags & ATA_FLAG_MMIO)
-               ata_tf_load_mmio(ap, tf);
-       else
-               ata_tf_load_pio(ap, tf);
-}
-
-/**
- *     ata_exec_command_pio - issue ATA command to host controller
- *     @ap: port to which command is being issued
- *     @tf: ATA taskfile register set
- *
- *     Issues PIO write to ATA command register, with proper
- *     synchronization with interrupt handler / other threads.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
- */
-
-static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
-               outb(tf->command, ap->ioaddr.command_addr);
-       ata_pause(ap);
-}
-
-
-/**
- *     ata_exec_command_mmio - issue ATA command to host controller
- *     @ap: port to which command is being issued
- *     @tf: ATA taskfile register set
- *
- *     Issues MMIO write to ATA command register, with proper
- *     synchronization with interrupt handler / other threads.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
- */
-
-static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
-               writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
-       ata_pause(ap);
-}
-
-
-/**
- *     ata_exec_command - issue ATA command to host controller
- *     @ap: port to which command is being issued
- *     @tf: ATA taskfile register set
- *
- *     Issues PIO/MMIO write to ATA command register, with proper
- *     synchronization with interrupt handler / other threads.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
- */
-void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
-{
-       if (ap->flags & ATA_FLAG_MMIO)
-               ata_exec_command_mmio(ap, tf);
-       else
-               ata_exec_command_pio(ap, tf);
-}
-
-/**
- *     ata_tf_to_host - issue ATA taskfile to host controller
- *     @ap: port to which command is being issued
- *     @tf: ATA taskfile register set
- *
- *     Issues ATA taskfile register set to ATA host controller,
- *     with proper synchronization with interrupt handler and
- *     other threads.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
- */
-
-static inline void ata_tf_to_host(struct ata_port *ap,
-                                 const struct ata_taskfile *tf)
-{
-       ap->ops->tf_load(ap, tf);
-       ap->ops->exec_command(ap, tf);
-}
-
-/**
- *     ata_tf_read_pio - input device's ATA taskfile shadow registers
- *     @ap: Port from which input is read
- *     @tf: ATA taskfile register set for storing input
- *
- *     Reads ATA taskfile registers for currently-selected device
- *     into @tf.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-
-static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
-{
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-
-       tf->command = ata_check_status(ap);
-       tf->feature = inb(ioaddr->error_addr);
-       tf->nsect = inb(ioaddr->nsect_addr);
-       tf->lbal = inb(ioaddr->lbal_addr);
-       tf->lbam = inb(ioaddr->lbam_addr);
-       tf->lbah = inb(ioaddr->lbah_addr);
-       tf->device = inb(ioaddr->device_addr);
-
-       if (tf->flags & ATA_TFLAG_LBA48) {
-               outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
-               tf->hob_feature = inb(ioaddr->error_addr);
-               tf->hob_nsect = inb(ioaddr->nsect_addr);
-               tf->hob_lbal = inb(ioaddr->lbal_addr);
-               tf->hob_lbam = inb(ioaddr->lbam_addr);
-               tf->hob_lbah = inb(ioaddr->lbah_addr);
-       }
-}
-
-/**
- *     ata_tf_read_mmio - input device's ATA taskfile shadow registers
- *     @ap: Port from which input is read
- *     @tf: ATA taskfile register set for storing input
- *
- *     Reads ATA taskfile registers for currently-selected device
- *     into @tf via MMIO.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-
-static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
-{
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-
-       tf->command = ata_check_status(ap);
-       tf->feature = readb((void __iomem *)ioaddr->error_addr);
-       tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
-       tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
-       tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
-       tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
-       tf->device = readb((void __iomem *)ioaddr->device_addr);
-
-       if (tf->flags & ATA_TFLAG_LBA48) {
-               writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
-               tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
-               tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
-               tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
-               tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
-               tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
-       }
-}
-
-
-/**
- *     ata_tf_read - input device's ATA taskfile shadow registers
- *     @ap: Port from which input is read
- *     @tf: ATA taskfile register set for storing input
- *
- *     Reads ATA taskfile registers for currently-selected device
- *     into @tf.
- *
- *     Reads nsect, lbal, lbam, lbah, and device.  If ATA_TFLAG_LBA48
- *     is set, also reads the hob registers.
- *
- *     May be used as the tf_read() entry in ata_port_operations.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
-       if (ap->flags & ATA_FLAG_MMIO)
-               ata_tf_read_mmio(ap, tf);
-       else
-               ata_tf_read_pio(ap, tf);
-}
-
-/**
- *     ata_check_status_pio - Read device status reg & clear interrupt
- *     @ap: port where the device is
- *
- *     Reads ATA taskfile status register for currently-selected device
- *     and return its value. This also clears pending interrupts
- *      from this device
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-static u8 ata_check_status_pio(struct ata_port *ap)
-{
-       return inb(ap->ioaddr.status_addr);
-}
-
-/**
- *     ata_check_status_mmio - Read device status reg & clear interrupt
- *     @ap: port where the device is
- *
- *     Reads ATA taskfile status register for currently-selected device
- *     via MMIO and return its value. This also clears pending interrupts
- *      from this device
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-static u8 ata_check_status_mmio(struct ata_port *ap)
-{
-               return readb((void __iomem *) ap->ioaddr.status_addr);
-}
-
-
-/**
- *     ata_check_status - Read device status reg & clear interrupt
- *     @ap: port where the device is
- *
- *     Reads ATA taskfile status register for currently-selected device
- *     and return its value. This also clears pending interrupts
- *      from this device
- *
- *     May be used as the check_status() entry in ata_port_operations.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-u8 ata_check_status(struct ata_port *ap)
-{
-       if (ap->flags & ATA_FLAG_MMIO)
-               return ata_check_status_mmio(ap);
-       return ata_check_status_pio(ap);
-}
-
-
-/**
- *     ata_altstatus - Read device alternate status reg
- *     @ap: port where the device is
- *
- *     Reads ATA taskfile alternate status register for
- *     currently-selected device and return its value.
- *
- *     Note: may NOT be used as the check_altstatus() entry in
- *     ata_port_operations.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-u8 ata_altstatus(struct ata_port *ap)
-{
-       if (ap->ops->check_altstatus)
-               return ap->ops->check_altstatus(ap);
-
-       if (ap->flags & ATA_FLAG_MMIO)
-               return readb((void __iomem *)ap->ioaddr.altstatus_addr);
-       return inb(ap->ioaddr.altstatus_addr);
-}
-
 
 /**
  *     ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
@@ -632,58 +228,148 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
        return -1;
 }
 
-static const char * const xfer_mode_str[] = {
-       "UDMA/16",
-       "UDMA/25",
-       "UDMA/33",
-       "UDMA/44",
-       "UDMA/66",
-       "UDMA/100",
-       "UDMA/133",
-       "UDMA7",
-       "MWDMA0",
-       "MWDMA1",
-       "MWDMA2",
-       "PIO0",
-       "PIO1",
-       "PIO2",
-       "PIO3",
-       "PIO4",
+/**
+ *     ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
+ *     @pio_mask: pio_mask
+ *     @mwdma_mask: mwdma_mask
+ *     @udma_mask: udma_mask
+ *
+ *     Pack @pio_mask, @mwdma_mask and @udma_mask into a single
+ *     unsigned int xfer_mask.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Packed xfer_mask.
+ */
+static unsigned int ata_pack_xfermask(unsigned int pio_mask,
+                                     unsigned int mwdma_mask,
+                                     unsigned int udma_mask)
+{
+       return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
+               ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
+               ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
+}
+
+static const struct ata_xfer_ent {
+       unsigned int shift, bits;
+       u8 base;
+} ata_xfer_tbl[] = {
+       { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
+       { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
+       { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
+       { -1, },
 };
 
 /**
- *     ata_udma_string - convert UDMA bit offset to string
- *     @mask: mask of bits supported; only highest bit counts.
+ *     ata_xfer_mask2mode - Find matching XFER_* for the given xfer_mask
+ *     @xfer_mask: xfer_mask of interest
  *
- *     Determine string which represents the highest speed
- *     (highest bit in @udma_mask).
+ *     Return matching XFER_* value for @xfer_mask.  Only the highest
+ *     bit of @xfer_mask is considered.
  *
  *     LOCKING:
  *     None.
  *
  *     RETURNS:
- *     Constant C string representing highest speed listed in
- *     @udma_mask, or the constant C string "<n/a>".
+ *     Matching XFER_* value, 0 if no match found.
+ */
+static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
+{
+       int highbit = fls(xfer_mask) - 1;
+       const struct ata_xfer_ent *ent;
+
+       for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+               if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
+                       return ent->base + highbit - ent->shift;
+       return 0;
+}
+
+/**
+ *     ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
+ *     @xfer_mode: XFER_* of interest
+ *
+ *     Return matching xfer_mask for @xfer_mode.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Matching xfer_mask, 0 if no match found.
  */
+static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
+{
+       const struct ata_xfer_ent *ent;
+
+       for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+               if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+                       return 1 << (ent->shift + xfer_mode - ent->base);
+       return 0;
+}
 
-static const char *ata_mode_string(unsigned int mask)
+/**
+ *     ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
+ *     @xfer_mode: XFER_* of interest
+ *
+ *     Return matching xfer_shift for @xfer_mode.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Matching xfer_shift, -1 if no match found.
+ */
+static int ata_xfer_mode2shift(unsigned int xfer_mode)
 {
-       int i;
+       const struct ata_xfer_ent *ent;
 
-       for (i = 7; i >= 0; i--)
-               if (mask & (1 << i))
-                       goto out;
-       for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--)
-               if (mask & (1 << i))
-                       goto out;
-       for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--)
-               if (mask & (1 << i))
-                       goto out;
+       for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+               if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+                       return ent->shift;
+       return -1;
+}
 
+/**
+ *     ata_mode_string - convert xfer_mask to string
+ *     @xfer_mask: mask of bits supported; only highest bit counts.
+ *
+ *     Determine string which represents the highest speed
+ *     (highest bit in @modemask).
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Constant C string representing highest speed listed in
+ *     @mode_mask, or the constant C string "<n/a>".
+ */
+static const char *ata_mode_string(unsigned int xfer_mask)
+{
+       static const char * const xfer_mode_str[] = {
+               "PIO0",
+               "PIO1",
+               "PIO2",
+               "PIO3",
+               "PIO4",
+               "MWDMA0",
+               "MWDMA1",
+               "MWDMA2",
+               "UDMA/16",
+               "UDMA/25",
+               "UDMA/33",
+               "UDMA/44",
+               "UDMA/66",
+               "UDMA/100",
+               "UDMA/133",
+               "UDMA7",
+       };
+       int highbit;
+
+       highbit = fls(xfer_mask) - 1;
+       if (highbit >= 0 && highbit < ARRAY_SIZE(xfer_mode_str))
+               return xfer_mode_str[highbit];
        return "<n/a>";
-
-out:
-       return xfer_mode_str[i];
 }
 
 /**
@@ -838,6 +524,7 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
  *     ata_dev_try_classify - Parse returned ATA device signature
  *     @ap: ATA channel to examine
  *     @device: Device to examine (starting at zero)
+ *     @r_err: Value of error register on completion
  *
  *     After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
  *     an ATA/ATAPI-defined set of values is placed in the ATA
@@ -850,11 +537,14 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
  *
  *     LOCKING:
  *     caller.
+ *
+ *     RETURNS:
+ *     Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
  */
 
-static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
+static unsigned int
+ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
 {
-       struct ata_device *dev = &ap->device[device];
        struct ata_taskfile tf;
        unsigned int class;
        u8 err;
@@ -865,8 +555,8 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
 
        ap->ops->tf_read(ap, &tf);
        err = tf.feature;
-
-       dev->class = ATA_DEV_NONE;
+       if (r_err)
+               *r_err = err;
 
        /* see if device passed diags */
        if (err == 1)
@@ -874,22 +564,20 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
        else if ((device == 0) && (err == 0x81))
                /* do nothing */ ;
        else
-               return err;
+               return ATA_DEV_NONE;
 
-       /* determine if device if ATA or ATAPI */
+       /* determine if device is ATA or ATAPI */
        class = ata_dev_classify(&tf);
+
        if (class == ATA_DEV_UNKNOWN)
-               return err;
+               return ATA_DEV_NONE;
        if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
-               return err;
-
-       dev->class = class;
-
-       return err;
+               return ATA_DEV_NONE;
+       return class;
 }
 
 /**
- *     ata_dev_id_string - Convert IDENTIFY DEVICE page into string
+ *     ata_id_string - Convert IDENTIFY DEVICE page into string
  *     @id: IDENTIFY DEVICE results we will examine
  *     @s: string into which data is output
  *     @ofs: offset into identify device page
@@ -903,8 +591,8 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
  *     caller.
  */
 
-void ata_dev_id_string(const u16 *id, unsigned char *s,
-                      unsigned int ofs, unsigned int len)
+void ata_id_string(const u16 *id, unsigned char *s,
+                  unsigned int ofs, unsigned int len)
 {
        unsigned int c;
 
@@ -922,6 +610,49 @@ void ata_dev_id_string(const u16 *id, unsigned char *s,
        }
 }
 
+/**
+ *     ata_id_c_string - Convert IDENTIFY DEVICE page into C string
+ *     @id: IDENTIFY DEVICE results we will examine
+ *     @s: string into which data is output
+ *     @ofs: offset into identify device page
+ *     @len: length of string to return. must be an odd number.
+ *
+ *     This function is identical to ata_id_string except that it
+ *     trims trailing spaces and terminates the resulting string with
+ *     null.  @len must be actual maximum length (even number) + 1.
+ *
+ *     LOCKING:
+ *     caller.
+ */
+void ata_id_c_string(const u16 *id, unsigned char *s,
+                    unsigned int ofs, unsigned int len)
+{
+       unsigned char *p;
+
+       WARN_ON(!(len & 1));
+
+       ata_id_string(id, s, ofs, len - 1);
+
+       p = s + strnlen(s, len - 1);
+       while (p > s && p[-1] == ' ')
+               p--;
+       *p = '\0';
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+       if (ata_id_has_lba(id)) {
+               if (ata_id_has_lba48(id))
+                       return ata_id_u64(id, 100);
+               else
+                       return ata_id_u32(id, 60);
+       } else {
+               if (ata_id_current_chs_valid(id))
+                       return ata_id_u32(id, 57);
+               else
+                       return id[1] * id[3] * id[6];
+       }
+}
 
 /**
  *     ata_noop_dev_select - Select device 0/1 on ATA bus
@@ -1011,90 +742,172 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
 
 /**
  *     ata_dump_id - IDENTIFY DEVICE info debugging output
- *     @dev: Device whose IDENTIFY DEVICE page we will dump
+ *     @id: IDENTIFY DEVICE page to dump
  *
- *     Dump selected 16-bit words from a detected device's
- *     IDENTIFY PAGE page.
+ *     Dump selected 16-bit words from the given IDENTIFY DEVICE
+ *     page.
  *
  *     LOCKING:
  *     caller.
  */
 
-static inline void ata_dump_id(const struct ata_device *dev)
+static inline void ata_dump_id(const u16 *id)
 {
        DPRINTK("49==0x%04x  "
                "53==0x%04x  "
                "63==0x%04x  "
                "64==0x%04x  "
                "75==0x%04x  \n",
-               dev->id[49],
-               dev->id[53],
-               dev->id[63],
-               dev->id[64],
-               dev->id[75]);
+               id[49],
+               id[53],
+               id[63],
+               id[64],
+               id[75]);
        DPRINTK("80==0x%04x  "
                "81==0x%04x  "
                "82==0x%04x  "
                "83==0x%04x  "
                "84==0x%04x  \n",
-               dev->id[80],
-               dev->id[81],
-               dev->id[82],
-               dev->id[83],
-               dev->id[84]);
+               id[80],
+               id[81],
+               id[82],
+               id[83],
+               id[84]);
        DPRINTK("88==0x%04x  "
                "93==0x%04x\n",
-               dev->id[88],
-               dev->id[93]);
+               id[88],
+               id[93]);
 }
 
-/*
- *     Compute the PIO modes available for this device. This is not as
- *     trivial as it seems if we must consider early devices correctly.
+/**
+ *     ata_id_xfermask - Compute xfermask from the given IDENTIFY data
+ *     @id: IDENTIFY data to compute xfer mask from
+ *
+ *     Compute the xfermask for this device. This is not as trivial
+ *     as it seems if we must consider early devices correctly.
+ *
+ *     FIXME: pre IDE drive timing (do we care ?).
  *
- *     FIXME: pre IDE drive timing (do we care ?). 
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Computed xfermask
  */
-
-static unsigned int ata_pio_modes(const struct ata_device *adev)
+static unsigned int ata_id_xfermask(const u16 *id)
 {
-       u16 modes;
+       unsigned int pio_mask, mwdma_mask, udma_mask;
 
        /* Usual case. Word 53 indicates word 64 is valid */
-       if (adev->id[ATA_ID_FIELD_VALID] & (1 << 1)) {
-               modes = adev->id[ATA_ID_PIO_MODES] & 0x03;
-               modes <<= 3;
-               modes |= 0x7;
-               return modes;
+       if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
+               pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
+               pio_mask <<= 3;
+               pio_mask |= 0x7;
+       } else {
+               /* If word 64 isn't valid then Word 51 high byte holds
+                * the PIO timing number for the maximum. Turn it into
+                * a mask.
+                */
+               pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
+
+               /* But wait.. there's more. Design your standards by
+                * committee and you too can get a free iordy field to
+                * process. However its the speeds not the modes that
+                * are supported... Note drivers using the timing API
+                * will get this right anyway
+                */
        }
 
-       /* If word 64 isn't valid then Word 51 high byte holds the PIO timing
-          number for the maximum. Turn it into a mask and return it */
-       modes = (2 << ((adev->id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF)) - 1 ;
-       return modes;
-       /* But wait.. there's more. Design your standards by committee and
-          you too can get a free iordy field to process. However its the 
-          speeds not the modes that are supported... Note drivers using the
-          timing API will get this right anyway */
+       mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
+
+       udma_mask = 0;
+       if (id[ATA_ID_FIELD_VALID] & (1 << 2))
+               udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
+
+       return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
 }
 
-struct ata_exec_internal_arg {
-       unsigned int err_mask;
-       struct ata_taskfile *tf;
-       struct completion *waiting;
-};
+/**
+ *     ata_port_queue_task - Queue port_task
+ *     @ap: The ata_port to queue port_task for
+ *
+ *     Schedule @fn(@data) for execution after @delay jiffies using
+ *     port_task.  There is one port_task per port and it's the
+ *     user(low level driver)'s responsibility to make sure that only
+ *     one task is active at any given time.
+ *
+ *     libata core layer takes care of synchronization between
+ *     port_task and EH.  ata_port_queue_task() may be ignored for EH
+ *     synchronization.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
+                        unsigned long delay)
+{
+       int rc;
+
+       if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+               return;
+
+       PREPARE_WORK(&ap->port_task, fn, data);
+
+       if (!delay)
+               rc = queue_work(ata_wq, &ap->port_task);
+       else
+               rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
+
+       /* rc == 0 means that another user is using port task */
+       WARN_ON(rc == 0);
+}
+
+/**
+ *     ata_port_flush_task - Flush port_task
+ *     @ap: The ata_port to flush port_task for
+ *
+ *     After this function completes, port_task is guranteed not to
+ *     be running or scheduled.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ */
+void ata_port_flush_task(struct ata_port *ap)
+{
+       unsigned long flags;
+
+       DPRINTK("ENTER\n");
+
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+       DPRINTK("flush #1\n");
+       flush_workqueue(ata_wq);
+
+       /*
+        * At this point, if a task is running, it's guaranteed to see
+        * the FLUSH flag; thus, it will never queue pio tasks again.
+        * Cancel and flush.
+        */
+       if (!cancel_delayed_work(&ap->port_task)) {
+               DPRINTK("flush #2\n");
+               flush_workqueue(ata_wq);
+       }
 
-int ata_qc_complete_internal(struct ata_queued_cmd *qc)
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+       DPRINTK("EXIT\n");
+}
+
+void ata_qc_complete_internal(struct ata_queued_cmd *qc)
 {
-       struct ata_exec_internal_arg *arg = qc->private_data;
-       struct completion *waiting = arg->waiting;
+       struct completion *waiting = qc->private_data;
 
-       if (!(qc->err_mask & ~AC_ERR_DEV))
-               qc->ap->ops->tf_read(qc->ap, arg->tf);
-       arg->err_mask = qc->err_mask;
-       arg->waiting = NULL;
+       qc->ap->ops->tf_read(qc->ap, &qc->tf);
        complete(waiting);
-
-       return 0;
 }
 
 /**
@@ -1125,7 +938,7 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
        struct ata_queued_cmd *qc;
        DECLARE_COMPLETION(wait);
        unsigned long flags;
-       struct ata_exec_internal_arg arg;
+       unsigned int err_mask;
 
        spin_lock_irqsave(&ap->host_set->lock, flags);
 
@@ -1139,13 +952,12 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
                qc->nsect = buflen / ATA_SECT_SIZE;
        }
 
-       arg.waiting = &wait;
-       arg.tf = tf;
-       qc->private_data = &arg;
+       qc->private_data = &wait;
        qc->complete_fn = ata_qc_complete_internal;
 
-       if (ata_qc_issue(qc))
-               goto issue_fail;
+       qc->err_mask = ata_qc_issue(qc);
+       if (qc->err_mask)
+               ata_qc_complete(qc);
 
        spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
@@ -1158,8 +970,8 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
                 * before the caller cleans up, it will result in a
                 * spurious interrupt.  We can live with that.
                 */
-               if (arg.waiting) {
-                       qc->err_mask = AC_ERR_OTHER;
+               if (qc->flags & ATA_QCFLAG_ACTIVE) {
+                       qc->err_mask = AC_ERR_TIMEOUT;
                        ata_qc_complete(qc);
                        printk(KERN_WARNING "ata%u: qc timeout (cmd 0x%x)\n",
                               ap->id, command);
@@ -1168,12 +980,12 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
                spin_unlock_irqrestore(&ap->host_set->lock, flags);
        }
 
-       return arg.err_mask;
+       *tf = qc->tf;
+       err_mask = qc->err_mask;
 
- issue_fail:
        ata_qc_free(qc);
-       spin_unlock_irqrestore(&ap->host_set->lock, flags);
-       return AC_ERR_OTHER;
+
+       return err_mask;
 }
 
 /**
@@ -1210,73 +1022,78 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
 }
 
 /**
- *     ata_dev_identify - obtain IDENTIFY x DEVICE page
- *     @ap: port on which device we wish to probe resides
- *     @device: device bus address, starting at zero
- *
- *     Following bus reset, we issue the IDENTIFY [PACKET] DEVICE
- *     command, and read back the 512-byte device information page.
- *     The device information page is fed to us via the standard
- *     PIO-IN protocol, but we hand-code it here. (TODO: investigate
- *     using standard PIO-IN paths)
- *
- *     After reading the device information page, we use several
- *     bits of information from it to initialize data structures
- *     that will be used during the lifetime of the ata_device.
- *     Other data from the info page is used to disqualify certain
- *     older ATA devices we do not wish to support.
+ *     ata_dev_read_id - Read ID data from the specified device
+ *     @ap: port on which target device resides
+ *     @dev: target device
+ *     @p_class: pointer to class of the target device (may be changed)
+ *     @post_reset: is this read ID post-reset?
+ *     @p_id: read IDENTIFY page (newly allocated)
+ *
+ *     Read ID data from the specified device.  ATA_CMD_ID_ATA is
+ *     performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
+ *     devices.  This function also takes care of EDD signature
+ *     misreporting (to be removed once EDD support is gone) and
+ *     issues ATA_CMD_INIT_DEV_PARAMS for pre-ATA4 drives.
  *
  *     LOCKING:
- *     Inherited from caller.  Some functions called by this function
- *     obtain the host_set lock.
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
  */
-
-static void ata_dev_identify(struct ata_port *ap, unsigned int device)
+static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev,
+                          unsigned int *p_class, int post_reset, u16 **p_id)
 {
-       struct ata_device *dev = &ap->device[device];
-       unsigned int major_version;
-       u16 tmp;
-       unsigned long xfer_modes;
+       unsigned int class = *p_class;
        unsigned int using_edd;
        struct ata_taskfile tf;
-       unsigned int err_mask;
+       unsigned int err_mask = 0;
+       u16 *id;
+       const char *reason;
        int rc;
 
-       if (!ata_dev_present(dev)) {
-               DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
-                       ap->id, device);
-               return;
-       }
+       DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
 
-       if (ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
+       if (ap->ops->probe_reset ||
+           ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
                using_edd = 0;
        else
                using_edd = 1;
 
-       DPRINTK("ENTER, host %u, dev %u\n", ap->id, device);
-
-       assert (dev->class == ATA_DEV_ATA || dev->class == ATA_DEV_ATAPI ||
-               dev->class == ATA_DEV_NONE);
+       ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
 
-       ata_dev_select(ap, device, 1, 1); /* select device 0/1 */
+       id = kmalloc(sizeof(id[0]) * ATA_ID_WORDS, GFP_KERNEL);
+       if (id == NULL) {
+               rc = -ENOMEM;
+               reason = "out of memory";
+               goto err_out;
+       }
 
-retry:
-       ata_tf_init(ap, &tf, device);
+ retry:
+       ata_tf_init(ap, &tf, dev->devno);
 
-       if (dev->class == ATA_DEV_ATA) {
+       switch (class) {
+       case ATA_DEV_ATA:
                tf.command = ATA_CMD_ID_ATA;
-               DPRINTK("do ATA identify\n");
-       } else {
+               break;
+       case ATA_DEV_ATAPI:
                tf.command = ATA_CMD_ID_ATAPI;
-               DPRINTK("do ATAPI identify\n");
+               break;
+       default:
+               rc = -ENODEV;
+               reason = "unsupported class";
+               goto err_out;
        }
 
        tf.protocol = ATA_PROT_PIO;
 
        err_mask = ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE,
-                                    dev->id, sizeof(dev->id));
+                                    id, sizeof(id[0]) * ATA_ID_WORDS);
 
        if (err_mask) {
+               rc = -EIO;
+               reason = "I/O error";
+
                if (err_mask & ~AC_ERR_DEV)
                        goto err_out;
 
@@ -1291,180 +1108,223 @@ retry:
                 * ATA software reset (SRST, the default) does not appear
                 * to have this problem.
                 */
-               if ((using_edd) && (dev->class == ATA_DEV_ATA)) {
+               if ((using_edd) && (class == ATA_DEV_ATA)) {
                        u8 err = tf.feature;
                        if (err & ATA_ABORTED) {
-                               dev->class = ATA_DEV_ATAPI;
+                               class = ATA_DEV_ATAPI;
                                goto retry;
                        }
                }
                goto err_out;
        }
 
-       swap_buf_le16(dev->id, ATA_ID_WORDS);
+       swap_buf_le16(id, ATA_ID_WORDS);
+
+       /* sanity check */
+       if ((class == ATA_DEV_ATA) != ata_id_is_ata(id)) {
+               rc = -EINVAL;
+               reason = "device reports illegal type";
+               goto err_out;
+       }
+
+       if (post_reset && class == ATA_DEV_ATA) {
+               /*
+                * The exact sequence expected by certain pre-ATA4 drives is:
+                * SRST RESET
+                * IDENTIFY
+                * INITIALIZE DEVICE PARAMETERS
+                * anything else..
+                * Some drives were very specific about that exact sequence.
+                */
+               if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
+                       err_mask = ata_dev_init_params(ap, dev);
+                       if (err_mask) {
+                               rc = -EIO;
+                               reason = "INIT_DEV_PARAMS failed";
+                               goto err_out;
+                       }
+
+                       /* current CHS translation info (id[53-58]) might be
+                        * changed. reread the identify device info.
+                        */
+                       post_reset = 0;
+                       goto retry;
+               }
+       }
+
+       *p_class = class;
+       *p_id = id;
+       return 0;
+
+ err_out:
+       printk(KERN_WARNING "ata%u: dev %u failed to IDENTIFY (%s)\n",
+              ap->id, dev->devno, reason);
+       kfree(id);
+       return rc;
+}
+
+static inline u8 ata_dev_knobble(const struct ata_port *ap,
+                                struct ata_device *dev)
+{
+       return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+}
+
+/**
+ *     ata_dev_configure - Configure the specified ATA/ATAPI device
+ *     @ap: Port on which target device resides
+ *     @dev: Target device to configure
+ *     @print_info: Enable device info printout
+ *
+ *     Configure @dev according to @dev->id.  Generic and low-level
+ *     driver specific fixups are also applied.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise
+ */
+static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
+                            int print_info)
+{
+       const u16 *id = dev->id;
+       unsigned int xfer_mask;
+       int i, rc;
+
+       if (!ata_dev_present(dev)) {
+               DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
+                       ap->id, dev->devno);
+               return 0;
+       }
+
+       DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
 
        /* print device capabilities */
-       printk(KERN_DEBUG "ata%u: dev %u cfg "
-              "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
-              ap->id, device, dev->id[49],
-              dev->id[82], dev->id[83], dev->id[84],
-              dev->id[85], dev->id[86], dev->id[87],
-              dev->id[88]);
+       if (print_info)
+               printk(KERN_DEBUG "ata%u: dev %u cfg 49:%04x 82:%04x 83:%04x "
+                      "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+                      ap->id, dev->devno, id[49], id[82], id[83],
+                      id[84], id[85], id[86], id[87], id[88]);
+
+       /* initialize to-be-configured parameters */
+       dev->flags = 0;
+       dev->max_sectors = 0;
+       dev->cdb_len = 0;
+       dev->n_sectors = 0;
+       dev->cylinders = 0;
+       dev->heads = 0;
+       dev->sectors = 0;
 
        /*
         * common ATA, ATAPI feature tests
         */
 
        /* we require DMA support (bits 8 of word 49) */
-       if (!ata_id_has_dma(dev->id)) {
+       if (!ata_id_has_dma(id)) {
                printk(KERN_DEBUG "ata%u: no dma\n", ap->id);
+               rc = -EINVAL;
                goto err_out_nosup;
        }
 
-       /* quick-n-dirty find max transfer mode; for printk only */
-       xfer_modes = dev->id[ATA_ID_UDMA_MODES];
-       if (!xfer_modes)
-               xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA;
-       if (!xfer_modes)
-               xfer_modes = ata_pio_modes(dev);
+       /* find max transfer mode; for printk only */
+       xfer_mask = ata_id_xfermask(id);
 
-       ata_dump_id(dev);
+       ata_dump_id(id);
 
        /* ATA-specific feature tests */
        if (dev->class == ATA_DEV_ATA) {
-               if (!ata_id_is_ata(dev->id))    /* sanity check */
-                       goto err_out_nosup;
-
-               /* get major version */
-               tmp = dev->id[ATA_ID_MAJOR_VER];
-               for (major_version = 14; major_version >= 1; major_version--)
-                       if (tmp & (1 << major_version))
-                               break;
-
-               /*
-                * The exact sequence expected by certain pre-ATA4 drives is:
-                * SRST RESET
-                * IDENTIFY
-                * INITIALIZE DEVICE PARAMETERS
-                * anything else..
-                * Some drives were very specific about that exact sequence.
-                */
-               if (major_version < 4 || (!ata_id_has_lba(dev->id))) {
-                       ata_dev_init_params(ap, dev);
+               dev->n_sectors = ata_id_n_sectors(id);
 
-                       /* current CHS translation info (id[53-58]) might be
-                        * changed. reread the identify device info.
-                        */
-                       ata_dev_reread_id(ap, dev);
-               }
+               if (ata_id_has_lba(id)) {
+                       const char *lba_desc;
 
-               if (ata_id_has_lba(dev->id)) {
+                       lba_desc = "LBA";
                        dev->flags |= ATA_DFLAG_LBA;
-
-                       if (ata_id_has_lba48(dev->id)) {
+                       if (ata_id_has_lba48(id)) {
                                dev->flags |= ATA_DFLAG_LBA48;
-                               dev->n_sectors = ata_id_u64(dev->id, 100);
-                       } else {
-                               dev->n_sectors = ata_id_u32(dev->id, 60);
+                               lba_desc = "LBA48";
                        }
 
                        /* print device info to dmesg */
-                       printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n",
-                              ap->id, device,
-                              major_version,
-                              ata_mode_string(xfer_modes),
-                              (unsigned long long)dev->n_sectors,
-                              dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA");
-               } else { 
+                       if (print_info)
+                               printk(KERN_INFO "ata%u: dev %u ATA-%d, "
+                                      "max %s, %Lu sectors: %s\n",
+                                      ap->id, dev->devno,
+                                      ata_id_major_version(id),
+                                      ata_mode_string(xfer_mask),
+                                      (unsigned long long)dev->n_sectors,
+                                      lba_desc);
+               } else {
                        /* CHS */
 
                        /* Default translation */
-                       dev->cylinders  = dev->id[1];
-                       dev->heads      = dev->id[3];
-                       dev->sectors    = dev->id[6];
-                       dev->n_sectors  = dev->cylinders * dev->heads * dev->sectors;
+                       dev->cylinders  = id[1];
+                       dev->heads      = id[3];
+                       dev->sectors    = id[6];
 
-                       if (ata_id_current_chs_valid(dev->id)) {
+                       if (ata_id_current_chs_valid(id)) {
                                /* Current CHS translation is valid. */
-                               dev->cylinders = dev->id[54];
-                               dev->heads     = dev->id[55];
-                               dev->sectors   = dev->id[56];
-                               
-                               dev->n_sectors = ata_id_u32(dev->id, 57);
+                               dev->cylinders = id[54];
+                               dev->heads     = id[55];
+                               dev->sectors   = id[56];
                        }
 
                        /* print device info to dmesg */
-                       printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n",
-                              ap->id, device,
-                              major_version,
-                              ata_mode_string(xfer_modes),
-                              (unsigned long long)dev->n_sectors,
-                              (int)dev->cylinders, (int)dev->heads, (int)dev->sectors);
-
+                       if (print_info)
+                               printk(KERN_INFO "ata%u: dev %u ATA-%d, "
+                                      "max %s, %Lu sectors: CHS %u/%u/%u\n",
+                                      ap->id, dev->devno,
+                                      ata_id_major_version(id),
+                                      ata_mode_string(xfer_mask),
+                                      (unsigned long long)dev->n_sectors,
+                                      dev->cylinders, dev->heads, dev->sectors);
                }
 
-               ap->host->max_cmd_len = 16;
+               dev->cdb_len = 16;
        }
 
        /* ATAPI-specific feature tests */
        else if (dev->class == ATA_DEV_ATAPI) {
-               if (ata_id_is_ata(dev->id))             /* sanity check */
-                       goto err_out_nosup;
-
-               rc = atapi_cdb_len(dev->id);
+               rc = atapi_cdb_len(id);
                if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
                        printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id);
+                       rc = -EINVAL;
                        goto err_out_nosup;
                }
-               ap->cdb_len = (unsigned int) rc;
-               ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
+               dev->cdb_len = (unsigned int) rc;
 
                /* print device info to dmesg */
-               printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
-                      ap->id, device,
-                      ata_mode_string(xfer_modes));
+               if (print_info)
+                       printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
+                              ap->id, dev->devno, ata_mode_string(xfer_mask));
        }
 
-       DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
-       return;
-
-err_out_nosup:
-       printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
-              ap->id, device);
-err_out:
-       dev->class++;   /* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */
-       DPRINTK("EXIT, err\n");
-}
-
-
-static inline u8 ata_dev_knobble(const struct ata_port *ap)
-{
-       return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id)));
-}
-
-/**
- *     ata_dev_config - Run device specific handlers and check for
- *                      SATA->PATA bridges
- *     @ap: Bus
- *     @i:  Device
- *
- *     LOCKING:
- */
+       ap->host->max_cmd_len = 0;
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               ap->host->max_cmd_len = max_t(unsigned int,
+                                             ap->host->max_cmd_len,
+                                             ap->device[i].cdb_len);
 
-void ata_dev_config(struct ata_port *ap, unsigned int i)
-{
        /* limit bridge transfers to udma5, 200 sectors */
-       if (ata_dev_knobble(ap)) {
-               printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
-                       ap->id, ap->device->devno);
+       if (ata_dev_knobble(ap, dev)) {
+               if (print_info)
+                       printk(KERN_INFO "ata%u(%u): applying bridge limits\n",
+                              ap->id, dev->devno);
                ap->udma_mask &= ATA_UDMA5;
-               ap->host->max_sectors = ATA_MAX_SECTORS;
-               ap->host->hostt->max_sectors = ATA_MAX_SECTORS;
-               ap->device[i].flags |= ATA_DFLAG_LOCK_SECTORS;
+               dev->max_sectors = ATA_MAX_SECTORS;
        }
 
        if (ap->ops->dev_config)
-               ap->ops->dev_config(ap, &ap->device[i]);
+               ap->ops->dev_config(ap, dev);
+
+       DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
+       return 0;
+
+err_out_nosup:
+       printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
+              ap->id, dev->devno);
+       DPRINTK("EXIT, err\n");
+       return rc;
 }
 
 /**
@@ -1484,21 +1344,59 @@ void ata_dev_config(struct ata_port *ap, unsigned int i)
 
 static int ata_bus_probe(struct ata_port *ap)
 {
-       unsigned int i, found = 0;
+       unsigned int classes[ATA_MAX_DEVICES];
+       unsigned int i, rc, found = 0;
 
-       ap->ops->phy_reset(ap);
-       if (ap->flags & ATA_FLAG_PORT_DISABLED)
-               goto err_out;
+       ata_port_probe(ap);
+
+       /* reset and determine device classes */
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               classes[i] = ATA_DEV_UNKNOWN;
+
+       if (ap->ops->probe_reset) {
+               rc = ap->ops->probe_reset(ap, classes);
+               if (rc) {
+                       printk("ata%u: reset failed (errno=%d)\n", ap->id, rc);
+                       return rc;
+               }
+       } else {
+               ap->ops->phy_reset(ap);
+
+               if (!(ap->flags & ATA_FLAG_PORT_DISABLED))
+                       for (i = 0; i < ATA_MAX_DEVICES; i++)
+                               classes[i] = ap->device[i].class;
+
+               ata_port_probe(ap);
+       }
+
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               if (classes[i] == ATA_DEV_UNKNOWN)
+                       classes[i] = ATA_DEV_NONE;
 
+       /* read IDENTIFY page and configure devices */
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               ata_dev_identify(ap, i);
-               if (ata_dev_present(&ap->device[i])) {
-                       found = 1;
-                       ata_dev_config(ap,i);
+               struct ata_device *dev = &ap->device[i];
+
+               dev->class = classes[i];
+
+               if (!ata_dev_present(dev))
+                       continue;
+
+               WARN_ON(dev->id != NULL);
+               if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) {
+                       dev->class = ATA_DEV_NONE;
+                       continue;
+               }
+
+               if (ata_dev_configure(ap, dev, 1)) {
+                       dev->class++;   /* disable device */
+                       continue;
                }
+
+               found = 1;
        }
 
-       if ((!found) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+       if (!found)
                goto err_out_disable;
 
        ata_set_mode(ap);
@@ -1509,7 +1407,6 @@ static int ata_bus_probe(struct ata_port *ap)
 
 err_out_disable:
        ap->ops->port_disable(ap);
-err_out:
        return -1;
 }
 
@@ -1530,6 +1427,41 @@ void ata_port_probe(struct ata_port *ap)
 }
 
 /**
+ *     sata_print_link_status - Print SATA link status
+ *     @ap: SATA port to printk link status about
+ *
+ *     This function prints link speed and status of a SATA link.
+ *
+ *     LOCKING:
+ *     None.
+ */
+static void sata_print_link_status(struct ata_port *ap)
+{
+       u32 sstatus, tmp;
+       const char *speed;
+
+       if (!ap->ops->scr_read)
+               return;
+
+       sstatus = scr_read(ap, SCR_STATUS);
+
+       if (sata_dev_present(ap)) {
+               tmp = (sstatus >> 4) & 0xf;
+               if (tmp & (1 << 0))
+                       speed = "1.5";
+               else if (tmp & (1 << 1))
+                       speed = "3.0";
+               else
+                       speed = "<unknown>";
+               printk(KERN_INFO "ata%u: SATA link up %s Gbps (SStatus %X)\n",
+                      ap->id, speed, sstatus);
+       } else {
+               printk(KERN_INFO "ata%u: SATA link down (SStatus %X)\n",
+                      ap->id, sstatus);
+       }
+}
+
+/**
  *     __sata_phy_reset - Wake/reset a low-level SATA PHY
  *     @ap: SATA port associated with target SATA PHY.
  *
@@ -1563,27 +1495,14 @@ void __sata_phy_reset(struct ata_port *ap)
                        break;
        } while (time_before(jiffies, timeout));
 
-       /* TODO: phy layer with polling, timeouts, etc. */
-       sstatus = scr_read(ap, SCR_STATUS);
-       if (sata_dev_present(ap)) {
-               const char *speed;
-               u32 tmp;
+       /* print link status */
+       sata_print_link_status(ap);
 
-               tmp = (sstatus >> 4) & 0xf;
-               if (tmp & (1 << 0))
-                       speed = "1.5";
-               else if (tmp & (1 << 1))
-                       speed = "3.0";
-               else
-                       speed = "<unknown>";
-               printk(KERN_INFO "ata%u: SATA link up %s Gbps (SStatus %X)\n",
-                      ap->id, speed, sstatus);
+       /* TODO: phy layer with polling, timeouts, etc. */
+       if (sata_dev_present(ap))
                ata_port_probe(ap);
-       } else {
-               printk(KERN_INFO "ata%u: SATA link down (SStatus %X)\n",
-                      ap->id, sstatus);
+       else
                ata_port_disable(ap);
-       }
 
        if (ap->flags & ATA_FLAG_PORT_DISABLED)
                return;
@@ -1756,9 +1675,9 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
        ata_timing_quantize(t, t, T, UT);
 
        /*
-        * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
-        * and some other commands. We have to ensure that the DMA cycle timing is
-        * slower/equal than the fastest PIO timing.
+        * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
+        * S.M.A.R.T * and some other commands. We have to ensure that the
+        * DMA cycle timing is slower/equal than the fastest PIO timing.
         */
 
        if (speed > XFER_PIO_4) {
@@ -1767,7 +1686,7 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
        }
 
        /*
-        * Lenghten active & recovery time so that cycle time is correct.
+        * Lengthen active & recovery time so that cycle time is correct.
         */
 
        if (t->act8b + t->rec8b < t->cyc8b) {
@@ -1783,31 +1702,8 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
        return 0;
 }
 
-static const struct {
-       unsigned int shift;
-       u8 base;
-} xfer_mode_classes[] = {
-       { ATA_SHIFT_UDMA,       XFER_UDMA_0 },
-       { ATA_SHIFT_MWDMA,      XFER_MW_DMA_0 },
-       { ATA_SHIFT_PIO,        XFER_PIO_0 },
-};
-
-static u8 base_from_shift(unsigned int shift)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++)
-               if (xfer_mode_classes[i].shift == shift)
-                       return xfer_mode_classes[i].base;
-
-       return 0xff;
-}
-
 static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
 {
-       int ofs, idx;
-       u8 base;
-
        if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
                return;
 
@@ -1816,65 +1712,58 @@ static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
 
        ata_dev_set_xfermode(ap, dev);
 
-       base = base_from_shift(dev->xfer_shift);
-       ofs = dev->xfer_mode - base;
-       idx = ofs + dev->xfer_shift;
-       WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str));
+       if (ata_dev_revalidate(ap, dev, 0)) {
+               printk(KERN_ERR "ata%u: failed to revalidate after set "
+                      "xfermode, disabled\n", ap->id);
+               ata_port_disable(ap);
+       }
 
-       DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n",
-               idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs);
+       DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
+               dev->xfer_shift, (int)dev->xfer_mode);
 
        printk(KERN_INFO "ata%u: dev %u configured for %s\n",
-               ap->id, dev->devno, xfer_mode_str[idx]);
+              ap->id, dev->devno,
+              ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
 }
 
 static int ata_host_set_pio(struct ata_port *ap)
 {
-       unsigned int mask;
-       int x, i;
-       u8 base, xfer_mode;
-
-       mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO);
-       x = fgb(mask);
-       if (x < 0) {
-               printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
-               return -1;
-       }
-
-       base = base_from_shift(ATA_SHIFT_PIO);
-       xfer_mode = base + x;
-
-       DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n",
-               (int)base, (int)xfer_mode, mask, x);
+       int i;
 
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
-               if (ata_dev_present(dev)) {
-                       dev->pio_mode = xfer_mode;
-                       dev->xfer_mode = xfer_mode;
-                       dev->xfer_shift = ATA_SHIFT_PIO;
-                       if (ap->ops->set_piomode)
-                               ap->ops->set_piomode(ap, dev);
+
+               if (!ata_dev_present(dev))
+                       continue;
+
+               if (!dev->pio_mode) {
+                       printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
+                       return -1;
                }
+
+               dev->xfer_mode = dev->pio_mode;
+               dev->xfer_shift = ATA_SHIFT_PIO;
+               if (ap->ops->set_piomode)
+                       ap->ops->set_piomode(ap, dev);
        }
 
        return 0;
 }
 
-static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
-                           unsigned int xfer_shift)
+static void ata_host_set_dma(struct ata_port *ap)
 {
        int i;
 
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
-               if (ata_dev_present(dev)) {
-                       dev->dma_mode = xfer_mode;
-                       dev->xfer_mode = xfer_mode;
-                       dev->xfer_shift = xfer_shift;
-                       if (ap->ops->set_dmamode)
-                               ap->ops->set_dmamode(ap, dev);
-               }
+
+               if (!ata_dev_present(dev) || !dev->dma_mode)
+                       continue;
+
+               dev->xfer_mode = dev->dma_mode;
+               dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
+               if (ap->ops->set_dmamode)
+                       ap->ops->set_dmamode(ap, dev);
        }
 }
 
@@ -1886,32 +1775,37 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
  *
  *     LOCKING:
  *     PCI/etc. bus probe sem.
- *
  */
 static void ata_set_mode(struct ata_port *ap)
 {
-       unsigned int xfer_shift;
-       u8 xfer_mode;
-       int rc;
+       int i, rc;
 
-       /* step 1: always set host PIO timings */
-       rc = ata_host_set_pio(ap);
-       if (rc)
-               goto err_out;
+       /* step 1: calculate xfer_mask */
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               struct ata_device *dev = &ap->device[i];
+               unsigned int xfer_mask;
+
+               if (!ata_dev_present(dev))
+                       continue;
+
+               xfer_mask = ata_dev_xfermask(ap, dev);
 
-       /* step 2: choose the best data xfer mode */
-       xfer_mode = xfer_shift = 0;
-       rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift);
+               dev->pio_mode = ata_xfer_mask2mode(xfer_mask & ATA_MASK_PIO);
+               dev->dma_mode = ata_xfer_mask2mode(xfer_mask & (ATA_MASK_MWDMA |
+                                                               ATA_MASK_UDMA));
+       }
+
+       /* step 2: always set host PIO timings */
+       rc = ata_host_set_pio(ap);
        if (rc)
                goto err_out;
 
-       /* step 3: if that xfer mode isn't PIO, set host DMA timings */
-       if (xfer_shift != ATA_SHIFT_PIO)
-               ata_host_set_dma(ap, xfer_mode, xfer_shift);
+       /* step 3: set host DMA timings */
+       ata_host_set_dma(ap);
 
        /* step 4: update devices' xfer mode */
-       ata_dev_set_mode(ap, &ap->device[0]);
-       ata_dev_set_mode(ap, &ap->device[1]);
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               ata_dev_set_mode(ap, &ap->device[i]);
 
        if (ap->flags & ATA_FLAG_PORT_DISABLED)
                return;
@@ -1926,6 +1820,26 @@ err_out:
 }
 
 /**
+ *     ata_tf_to_host - issue ATA taskfile to host controller
+ *     @ap: port to which command is being issued
+ *     @tf: ATA taskfile register set
+ *
+ *     Issues ATA taskfile register set to ATA host controller,
+ *     with proper synchronization with interrupt handler and
+ *     other threads.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+
+static inline void ata_tf_to_host(struct ata_port *ap,
+                                 const struct ata_taskfile *tf)
+{
+       ap->ops->tf_load(ap, tf);
+       ap->ops->exec_command(ap, tf);
+}
+
+/**
  *     ata_busy_sleep - sleep until BSY clears, or timeout
  *     @ap: port containing status register to be polled
  *     @tmout_pat: impatience timeout
@@ -1935,12 +1849,10 @@ err_out:
  *     or a timeout occurs.
  *
  *     LOCKING: None.
- *
  */
 
-static unsigned int ata_busy_sleep (struct ata_port *ap,
-                                   unsigned long tmout_pat,
-                                   unsigned long tmout)
+unsigned int ata_busy_sleep (struct ata_port *ap,
+                            unsigned long tmout_pat, unsigned long tmout)
 {
        unsigned long timer_start, timeout;
        u8 status;
@@ -2090,117 +2002,552 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
         */
        msleep(150);
 
-       ata_bus_post_reset(ap, devmask);
+       ata_bus_post_reset(ap, devmask);
+
+       return 0;
+}
+
+/**
+ *     ata_bus_reset - reset host port and associated ATA channel
+ *     @ap: port to reset
+ *
+ *     This is typically the first time we actually start issuing
+ *     commands to the ATA channel.  We wait for BSY to clear, then
+ *     issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
+ *     result.  Determine what devices, if any, are on the channel
+ *     by looking at the device 0/1 error register.  Look at the signature
+ *     stored in each device's taskfile registers, to determine if
+ *     the device is ATA or ATAPI.
+ *
+ *     LOCKING:
+ *     PCI/etc. bus probe sem.
+ *     Obtains host_set lock.
+ *
+ *     SIDE EFFECTS:
+ *     Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
+ */
+
+void ata_bus_reset(struct ata_port *ap)
+{
+       struct ata_ioports *ioaddr = &ap->ioaddr;
+       unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+       u8 err;
+       unsigned int dev0, dev1 = 0, rc = 0, devmask = 0;
+
+       DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
+
+       /* determine if device 0/1 are present */
+       if (ap->flags & ATA_FLAG_SATA_RESET)
+               dev0 = 1;
+       else {
+               dev0 = ata_devchk(ap, 0);
+               if (slave_possible)
+                       dev1 = ata_devchk(ap, 1);
+       }
+
+       if (dev0)
+               devmask |= (1 << 0);
+       if (dev1)
+               devmask |= (1 << 1);
+
+       /* select device 0 again */
+       ap->ops->dev_select(ap, 0);
+
+       /* issue bus reset */
+       if (ap->flags & ATA_FLAG_SRST)
+               rc = ata_bus_softreset(ap, devmask);
+       else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) {
+               /* set up device control */
+               if (ap->flags & ATA_FLAG_MMIO)
+                       writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+               else
+                       outb(ap->ctl, ioaddr->ctl_addr);
+               rc = ata_bus_edd(ap);
+       }
+
+       if (rc)
+               goto err_out;
+
+       /*
+        * determine by signature whether we have ATA or ATAPI devices
+        */
+       ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+       if ((slave_possible) && (err != 0x81))
+               ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+
+       /* re-enable interrupts */
+       if (ap->ioaddr.ctl_addr)        /* FIXME: hack. create a hook instead */
+               ata_irq_on(ap);
+
+       /* is double-select really necessary? */
+       if (ap->device[1].class != ATA_DEV_NONE)
+               ap->ops->dev_select(ap, 1);
+       if (ap->device[0].class != ATA_DEV_NONE)
+               ap->ops->dev_select(ap, 0);
+
+       /* if no devices were detected, disable this port */
+       if ((ap->device[0].class == ATA_DEV_NONE) &&
+           (ap->device[1].class == ATA_DEV_NONE))
+               goto err_out;
+
+       if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
+               /* set up device control for ATA_FLAG_SATA_RESET */
+               if (ap->flags & ATA_FLAG_MMIO)
+                       writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+               else
+                       outb(ap->ctl, ioaddr->ctl_addr);
+       }
+
+       DPRINTK("EXIT\n");
+       return;
+
+err_out:
+       printk(KERN_ERR "ata%u: disabling port\n", ap->id);
+       ap->ops->port_disable(ap);
+
+       DPRINTK("EXIT\n");
+}
+
+static int sata_phy_resume(struct ata_port *ap)
+{
+       unsigned long timeout = jiffies + (HZ * 5);
+       u32 sstatus;
+
+       scr_write_flush(ap, SCR_CONTROL, 0x300);
+
+       /* Wait for phy to become ready, if necessary. */
+       do {
+               msleep(200);
+               sstatus = scr_read(ap, SCR_STATUS);
+               if ((sstatus & 0xf) != 1)
+                       return 0;
+       } while (time_before(jiffies, timeout));
+
+       return -1;
+}
+
+/**
+ *     ata_std_probeinit - initialize probing
+ *     @ap: port to be probed
+ *
+ *     @ap is about to be probed.  Initialize it.  This function is
+ *     to be used as standard callback for ata_drive_probe_reset().
+ *
+ *     NOTE!!! Do not use this function as probeinit if a low level
+ *     driver implements only hardreset.  Just pass NULL as probeinit
+ *     in that case.  Using this function is probably okay but doing
+ *     so makes reset sequence different from the original
+ *     ->phy_reset implementation and Jeff nervous.  :-P
+ */
+extern void ata_std_probeinit(struct ata_port *ap)
+{
+       if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read) {
+               sata_phy_resume(ap);
+               if (sata_dev_present(ap))
+                       ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+       }
+}
+
+/**
+ *     ata_std_softreset - reset host port via ATA SRST
+ *     @ap: port to reset
+ *     @verbose: fail verbosely
+ *     @classes: resulting classes of attached devices
+ *
+ *     Reset host port using ATA SRST.  This function is to be used
+ *     as standard callback for ata_drive_*_reset() functions.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_std_softreset(struct ata_port *ap, int verbose, unsigned int *classes)
+{
+       unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+       unsigned int devmask = 0, err_mask;
+       u8 err;
+
+       DPRINTK("ENTER\n");
+
+       if (ap->ops->scr_read && !sata_dev_present(ap)) {
+               classes[0] = ATA_DEV_NONE;
+               goto out;
+       }
+
+       /* determine if device 0/1 are present */
+       if (ata_devchk(ap, 0))
+               devmask |= (1 << 0);
+       if (slave_possible && ata_devchk(ap, 1))
+               devmask |= (1 << 1);
+
+       /* select device 0 again */
+       ap->ops->dev_select(ap, 0);
+
+       /* issue bus reset */
+       DPRINTK("about to softreset, devmask=%x\n", devmask);
+       err_mask = ata_bus_softreset(ap, devmask);
+       if (err_mask) {
+               if (verbose)
+                       printk(KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n",
+                              ap->id, err_mask);
+               else
+                       DPRINTK("EXIT, softreset failed (err_mask=0x%x)\n",
+                               err_mask);
+               return -EIO;
+       }
+
+       /* determine by signature whether we have ATA or ATAPI devices */
+       classes[0] = ata_dev_try_classify(ap, 0, &err);
+       if (slave_possible && err != 0x81)
+               classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+       DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+       return 0;
+}
+
+/**
+ *     sata_std_hardreset - reset host port via SATA phy reset
+ *     @ap: port to reset
+ *     @verbose: fail verbosely
+ *     @class: resulting class of attached device
+ *
+ *     SATA phy-reset host port using DET bits of SControl register.
+ *     This function is to be used as standard callback for
+ *     ata_drive_*_reset().
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int sata_std_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
+       DPRINTK("ENTER\n");
+
+       /* Issue phy wake/reset */
+       scr_write_flush(ap, SCR_CONTROL, 0x301);
+
+       /*
+        * Couldn't find anything in SATA I/II specs, but AHCI-1.1
+        * 10.4.2 says at least 1 ms.
+        */
+       msleep(1);
+
+       /* Bring phy back */
+       sata_phy_resume(ap);
+
+       /* TODO: phy layer with polling, timeouts, etc. */
+       if (!sata_dev_present(ap)) {
+               *class = ATA_DEV_NONE;
+               DPRINTK("EXIT, link offline\n");
+               return 0;
+       }
+
+       if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+               if (verbose)
+                       printk(KERN_ERR "ata%u: COMRESET failed "
+                              "(device not ready)\n", ap->id);
+               else
+                       DPRINTK("EXIT, device not ready\n");
+               return -EIO;
+       }
+
+       ap->ops->dev_select(ap, 0);     /* probably unnecessary */
+
+       *class = ata_dev_try_classify(ap, 0, NULL);
+
+       DPRINTK("EXIT, class=%u\n", *class);
+       return 0;
+}
+
+/**
+ *     ata_std_postreset - standard postreset callback
+ *     @ap: the target ata_port
+ *     @classes: classes of attached devices
+ *
+ *     This function is invoked after a successful reset.  Note that
+ *     the device might have been reset more than once using
+ *     different reset methods before postreset is invoked.
+ *
+ *     This function is to be used as standard callback for
+ *     ata_drive_*_reset().
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ */
+void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+{
+       DPRINTK("ENTER\n");
+
+       /* set cable type if it isn't already set */
+       if (ap->cbl == ATA_CBL_NONE && ap->flags & ATA_FLAG_SATA)
+               ap->cbl = ATA_CBL_SATA;
+
+       /* print link status */
+       if (ap->cbl == ATA_CBL_SATA)
+               sata_print_link_status(ap);
+
+       /* re-enable interrupts */
+       if (ap->ioaddr.ctl_addr)        /* FIXME: hack. create a hook instead */
+               ata_irq_on(ap);
+
+       /* is double-select really necessary? */
+       if (classes[0] != ATA_DEV_NONE)
+               ap->ops->dev_select(ap, 1);
+       if (classes[1] != ATA_DEV_NONE)
+               ap->ops->dev_select(ap, 0);
+
+       /* bail out if no device is present */
+       if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+               DPRINTK("EXIT, no device\n");
+               return;
+       }
+
+       /* set up device control */
+       if (ap->ioaddr.ctl_addr) {
+               if (ap->flags & ATA_FLAG_MMIO)
+                       writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+               else
+                       outb(ap->ctl, ap->ioaddr.ctl_addr);
+       }
+
+       DPRINTK("EXIT\n");
+}
+
+/**
+ *     ata_std_probe_reset - standard probe reset method
+ *     @ap: prot to perform probe-reset
+ *     @classes: resulting classes of attached devices
+ *
+ *     The stock off-the-shelf ->probe_reset method.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+       ata_reset_fn_t hardreset;
+
+       hardreset = NULL;
+       if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read)
+               hardreset = sata_std_hardreset;
+
+       return ata_drive_probe_reset(ap, ata_std_probeinit,
+                                    ata_std_softreset, hardreset,
+                                    ata_std_postreset, classes);
+}
+
+static int do_probe_reset(struct ata_port *ap, ata_reset_fn_t reset,
+                         ata_postreset_fn_t postreset,
+                         unsigned int *classes)
+{
+       int i, rc;
+
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               classes[i] = ATA_DEV_UNKNOWN;
+
+       rc = reset(ap, 0, classes);
+       if (rc)
+               return rc;
+
+       /* If any class isn't ATA_DEV_UNKNOWN, consider classification
+        * is complete and convert all ATA_DEV_UNKNOWN to
+        * ATA_DEV_NONE.
+        */
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               if (classes[i] != ATA_DEV_UNKNOWN)
+                       break;
+
+       if (i < ATA_MAX_DEVICES)
+               for (i = 0; i < ATA_MAX_DEVICES; i++)
+                       if (classes[i] == ATA_DEV_UNKNOWN)
+                               classes[i] = ATA_DEV_NONE;
+
+       if (postreset)
+               postreset(ap, classes);
+
+       return classes[0] != ATA_DEV_UNKNOWN ? 0 : -ENODEV;
+}
+
+/**
+ *     ata_drive_probe_reset - Perform probe reset with given methods
+ *     @ap: port to reset
+ *     @probeinit: probeinit method (can be NULL)
+ *     @softreset: softreset method (can be NULL)
+ *     @hardreset: hardreset method (can be NULL)
+ *     @postreset: postreset method (can be NULL)
+ *     @classes: resulting classes of attached devices
+ *
+ *     Reset the specified port and classify attached devices using
+ *     given methods.  This function prefers softreset but tries all
+ *     possible reset sequences to reset and classify devices.  This
+ *     function is intended to be used for constructing ->probe_reset
+ *     callback by low level drivers.
+ *
+ *     Reset methods should follow the following rules.
+ *
+ *     - Return 0 on sucess, -errno on failure.
+ *     - If classification is supported, fill classes[] with
+ *       recognized class codes.
+ *     - If classification is not supported, leave classes[] alone.
+ *     - If verbose is non-zero, print error message on failure;
+ *       otherwise, shut up.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -EINVAL if no reset method is avaliable, -ENODEV
+ *     if classification fails, and any error code from reset
+ *     methods.
+ */
+int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
+                         ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+                         ata_postreset_fn_t postreset, unsigned int *classes)
+{
+       int rc = -EINVAL;
+
+       if (probeinit)
+               probeinit(ap);
+
+       if (softreset) {
+               rc = do_probe_reset(ap, softreset, postreset, classes);
+               if (rc == 0)
+                       return 0;
+       }
+
+       if (!hardreset)
+               return rc;
+
+       rc = do_probe_reset(ap, hardreset, postreset, classes);
+       if (rc == 0 || rc != -ENODEV)
+               return rc;
 
-       return 0;
+       if (softreset)
+               rc = do_probe_reset(ap, softreset, postreset, classes);
+
+       return rc;
 }
 
 /**
- *     ata_bus_reset - reset host port and associated ATA channel
- *     @ap: port to reset
+ *     ata_dev_same_device - Determine whether new ID matches configured device
+ *     @ap: port on which the device to compare against resides
+ *     @dev: device to compare against
+ *     @new_class: class of the new device
+ *     @new_id: IDENTIFY page of the new device
  *
- *     This is typically the first time we actually start issuing
- *     commands to the ATA channel.  We wait for BSY to clear, then
- *     issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
- *     result.  Determine what devices, if any, are on the channel
- *     by looking at the device 0/1 error register.  Look at the signature
- *     stored in each device's taskfile registers, to determine if
- *     the device is ATA or ATAPI.
+ *     Compare @new_class and @new_id against @dev and determine
+ *     whether @dev is the device indicated by @new_class and
+ *     @new_id.
  *
  *     LOCKING:
- *     PCI/etc. bus probe sem.
- *     Obtains host_set lock.
+ *     None.
  *
- *     SIDE EFFECTS:
- *     Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
+ *     RETURNS:
+ *     1 if @dev matches @new_class and @new_id, 0 otherwise.
  */
-
-void ata_bus_reset(struct ata_port *ap)
+static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
+                              unsigned int new_class, const u16 *new_id)
 {
-       struct ata_ioports *ioaddr = &ap->ioaddr;
-       unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
-       u8 err;
-       unsigned int dev0, dev1 = 0, rc = 0, devmask = 0;
-
-       DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
+       const u16 *old_id = dev->id;
+       unsigned char model[2][41], serial[2][21];
+       u64 new_n_sectors;
 
-       /* determine if device 0/1 are present */
-       if (ap->flags & ATA_FLAG_SATA_RESET)
-               dev0 = 1;
-       else {
-               dev0 = ata_devchk(ap, 0);
-               if (slave_possible)
-                       dev1 = ata_devchk(ap, 1);
+       if (dev->class != new_class) {
+               printk(KERN_INFO
+                      "ata%u: dev %u class mismatch %d != %d\n",
+                      ap->id, dev->devno, dev->class, new_class);
+               return 0;
        }
 
-       if (dev0)
-               devmask |= (1 << 0);
-       if (dev1)
-               devmask |= (1 << 1);
+       ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
+       ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
+       ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
+       ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
+       new_n_sectors = ata_id_n_sectors(new_id);
 
-       /* select device 0 again */
-       ap->ops->dev_select(ap, 0);
+       if (strcmp(model[0], model[1])) {
+               printk(KERN_INFO
+                      "ata%u: dev %u model number mismatch '%s' != '%s'\n",
+                      ap->id, dev->devno, model[0], model[1]);
+               return 0;
+       }
 
-       /* issue bus reset */
-       if (ap->flags & ATA_FLAG_SRST)
-               rc = ata_bus_softreset(ap, devmask);
-       else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) {
-               /* set up device control */
-               if (ap->flags & ATA_FLAG_MMIO)
-                       writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
-               else
-                       outb(ap->ctl, ioaddr->ctl_addr);
-               rc = ata_bus_edd(ap);
+       if (strcmp(serial[0], serial[1])) {
+               printk(KERN_INFO
+                      "ata%u: dev %u serial number mismatch '%s' != '%s'\n",
+                      ap->id, dev->devno, serial[0], serial[1]);
+               return 0;
        }
 
-       if (rc)
-               goto err_out;
+       if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
+               printk(KERN_INFO
+                      "ata%u: dev %u n_sectors mismatch %llu != %llu\n",
+                      ap->id, dev->devno, (unsigned long long)dev->n_sectors,
+                      (unsigned long long)new_n_sectors);
+               return 0;
+       }
 
-       /*
-        * determine by signature whether we have ATA or ATAPI devices
-        */
-       err = ata_dev_try_classify(ap, 0);
-       if ((slave_possible) && (err != 0x81))
-               ata_dev_try_classify(ap, 1);
+       return 1;
+}
 
-       /* re-enable interrupts */
-       if (ap->ioaddr.ctl_addr)        /* FIXME: hack. create a hook instead */
-               ata_irq_on(ap);
+/**
+ *     ata_dev_revalidate - Revalidate ATA device
+ *     @ap: port on which the device to revalidate resides
+ *     @dev: device to revalidate
+ *     @post_reset: is this revalidation after reset?
+ *
+ *     Re-read IDENTIFY page and make sure @dev is still attached to
+ *     the port.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, negative errno otherwise
+ */
+int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
+                      int post_reset)
+{
+       unsigned int class;
+       u16 *id;
+       int rc;
 
-       /* is double-select really necessary? */
-       if (ap->device[1].class != ATA_DEV_NONE)
-               ap->ops->dev_select(ap, 1);
-       if (ap->device[0].class != ATA_DEV_NONE)
-               ap->ops->dev_select(ap, 0);
+       if (!ata_dev_present(dev))
+               return -ENODEV;
 
-       /* if no devices were detected, disable this port */
-       if ((ap->device[0].class == ATA_DEV_NONE) &&
-           (ap->device[1].class == ATA_DEV_NONE))
-               goto err_out;
+       class = dev->class;
+       id = NULL;
 
-       if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
-               /* set up device control for ATA_FLAG_SATA_RESET */
-               if (ap->flags & ATA_FLAG_MMIO)
-                       writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
-               else
-                       outb(ap->ctl, ioaddr->ctl_addr);
-       }
+       /* allocate & read ID data */
+       rc = ata_dev_read_id(ap, dev, &class, post_reset, &id);
+       if (rc)
+               goto fail;
 
-       DPRINTK("EXIT\n");
-       return;
+       /* is the device still there? */
+       if (!ata_dev_same_device(ap, dev, class, id)) {
+               rc = -ENODEV;
+               goto fail;
+       }
 
-err_out:
-       printk(KERN_ERR "ata%u: disabling port\n", ap->id);
-       ap->ops->port_disable(ap);
+       kfree(dev->id);
+       dev->id = id;
 
-       DPRINTK("EXIT\n");
-}
+       /* configure device according to the new ID */
+       return ata_dev_configure(ap, dev, 0);
 
-static void ata_pr_blacklisted(const struct ata_port *ap,
-                              const struct ata_device *dev)
-{
-       printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n",
-               ap->id, dev->devno);
+ fail:
+       printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n",
+              ap->id, dev->devno, rc);
+       kfree(id);
+       return rc;
 }
 
 static const char * const ata_dma_blacklist [] = {
@@ -2237,151 +2584,57 @@ static const char * const ata_dma_blacklist [] = {
 
 static int ata_dma_blacklisted(const struct ata_device *dev)
 {
-       unsigned char model_num[40];
-       char *s;
-       unsigned int len;
+       unsigned char model_num[41];
        int i;
 
-       ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
-                         sizeof(model_num));
-       s = &model_num[0];
-       len = strnlen(s, sizeof(model_num));
-
-       /* ATAPI specifies that empty space is blank-filled; remove blanks */
-       while ((len > 0) && (s[len - 1] == ' ')) {
-               len--;
-               s[len] = 0;
-       }
+       ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
 
        for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i++)
-               if (!strncmp(ata_dma_blacklist[i], s, len))
+               if (!strcmp(ata_dma_blacklist[i], model_num))
                        return 1;
 
        return 0;
 }
 
-static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift)
-{
-       const struct ata_device *master, *slave;
-       unsigned int mask;
-
-       master = &ap->device[0];
-       slave = &ap->device[1];
-
-       assert (ata_dev_present(master) || ata_dev_present(slave));
-
-       if (shift == ATA_SHIFT_UDMA) {
-               mask = ap->udma_mask;
-               if (ata_dev_present(master)) {
-                       mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
-                       if (ata_dma_blacklisted(master)) {
-                               mask = 0;
-                               ata_pr_blacklisted(ap, master);
-                       }
-               }
-               if (ata_dev_present(slave)) {
-                       mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
-                       if (ata_dma_blacklisted(slave)) {
-                               mask = 0;
-                               ata_pr_blacklisted(ap, slave);
-                       }
-               }
-       }
-       else if (shift == ATA_SHIFT_MWDMA) {
-               mask = ap->mwdma_mask;
-               if (ata_dev_present(master)) {
-                       mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07);
-                       if (ata_dma_blacklisted(master)) {
-                               mask = 0;
-                               ata_pr_blacklisted(ap, master);
-                       }
-               }
-               if (ata_dev_present(slave)) {
-                       mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07);
-                       if (ata_dma_blacklisted(slave)) {
-                               mask = 0;
-                               ata_pr_blacklisted(ap, slave);
-                       }
-               }
-       }
-       else if (shift == ATA_SHIFT_PIO) {
-               mask = ap->pio_mask;
-               if (ata_dev_present(master)) {
-                       /* spec doesn't return explicit support for
-                        * PIO0-2, so we fake it
-                        */
-                       u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03;
-                       tmp_mode <<= 3;
-                       tmp_mode |= 0x7;
-                       mask &= tmp_mode;
-               }
-               if (ata_dev_present(slave)) {
-                       /* spec doesn't return explicit support for
-                        * PIO0-2, so we fake it
-                        */
-                       u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03;
-                       tmp_mode <<= 3;
-                       tmp_mode |= 0x7;
-                       mask &= tmp_mode;
-               }
-       }
-       else {
-               mask = 0xffffffff; /* shut up compiler warning */
-               BUG();
-       }
-
-       return mask;
-}
-
-/* find greatest bit */
-static int fgb(u32 bitmap)
-{
-       unsigned int i;
-       int x = -1;
-
-       for (i = 0; i < 32; i++)
-               if (bitmap & (1 << i))
-                       x = i;
-
-       return x;
-}
-
 /**
- *     ata_choose_xfer_mode - attempt to find best transfer mode
- *     @ap: Port for which an xfer mode will be selected
- *     @xfer_mode_out: (output) SET FEATURES - XFER MODE code
- *     @xfer_shift_out: (output) bit shift that selects this mode
+ *     ata_dev_xfermask - Compute supported xfermask of the given device
+ *     @ap: Port on which the device to compute xfermask for resides
+ *     @dev: Device to compute xfermask for
  *
- *     Based on host and device capabilities, determine the
- *     maximum transfer mode that is amenable to all.
+ *     Compute supported xfermask of @dev.  This function is
+ *     responsible for applying all known limits including host
+ *     controller limits, device blacklist, etc...
  *
  *     LOCKING:
- *     PCI/etc. bus probe sem.
+ *     None.
  *
  *     RETURNS:
- *     Zero on success, negative on error.
+ *     Computed xfermask.
  */
-
-static int ata_choose_xfer_mode(const struct ata_port *ap,
-                               u8 *xfer_mode_out,
-                               unsigned int *xfer_shift_out)
+static unsigned int ata_dev_xfermask(struct ata_port *ap,
+                                    struct ata_device *dev)
 {
-       unsigned int mask, shift;
-       int x, i;
+       unsigned long xfer_mask;
+       int i;
 
-       for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) {
-               shift = xfer_mode_classes[i].shift;
-               mask = ata_get_mode_mask(ap, shift);
+       xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+                                     ap->udma_mask);
 
-               x = fgb(mask);
-               if (x >= 0) {
-                       *xfer_mode_out = xfer_mode_classes[i].base + x;
-                       *xfer_shift_out = shift;
-                       return 0;
-               }
+       /* use port-wide xfermask for now */
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               struct ata_device *d = &ap->device[i];
+               if (!ata_dev_present(d))
+                       continue;
+               xfer_mask &= ata_id_xfermask(d->id);
+               if (ata_dma_blacklisted(d))
+                       xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
        }
 
-       return -1;
+       if (ata_dma_blacklisted(dev))
+               printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, "
+                      "disabling DMA\n", ap->id, dev->devno);
+
+       return xfer_mask;
 }
 
 /**
@@ -2420,63 +2673,28 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
 }
 
 /**
- *     ata_dev_reread_id - Reread the device identify device info
- *     @ap: port where the device is
- *     @dev: device to reread the identify device info
- *
- *     LOCKING:
- */
-
-static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev)
-{
-       struct ata_taskfile tf;
-
-       ata_tf_init(ap, &tf, dev->devno);
-
-       if (dev->class == ATA_DEV_ATA) {
-               tf.command = ATA_CMD_ID_ATA;
-               DPRINTK("do ATA identify\n");
-       } else {
-               tf.command = ATA_CMD_ID_ATAPI;
-               DPRINTK("do ATAPI identify\n");
-       }
-
-       tf.flags |= ATA_TFLAG_DEVICE;
-       tf.protocol = ATA_PROT_PIO;
-
-       if (ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE,
-                             dev->id, sizeof(dev->id)))
-               goto err_out;
-
-       swap_buf_le16(dev->id, ATA_ID_WORDS);
-
-       ata_dump_id(dev);
-
-       DPRINTK("EXIT\n");
-
-       return;
-err_out:
-       printk(KERN_ERR "ata%u: failed to reread ID, disabled\n", ap->id);
-       ata_port_disable(ap);
-}
-
-/**
  *     ata_dev_init_params - Issue INIT DEV PARAMS command
  *     @ap: Port associated with device @dev
  *     @dev: Device to which command will be sent
  *
  *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, AC_ERR_* mask otherwise.
  */
 
-static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
+static unsigned int ata_dev_init_params(struct ata_port *ap,
+                                       struct ata_device *dev)
 {
        struct ata_taskfile tf;
+       unsigned int err_mask;
        u16 sectors = dev->id[6];
        u16 heads   = dev->id[3];
 
        /* Number of sectors per track 1-255. Number of heads 1-16 */
        if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
-               return;
+               return 0;
 
        /* set up init dev params taskfile */
        DPRINTK("init dev params \n");
@@ -2488,13 +2706,10 @@ static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
        tf.nsect = sectors;
        tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
 
-       if (ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0)) {
-               printk(KERN_ERR "ata%u: failed to init parameters, disabled\n",
-                      ap->id);
-               ata_port_disable(ap);
-       }
+       err_mask = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0);
 
-       DPRINTK("EXIT\n");
+       DPRINTK("EXIT, err_mask=%x\n", err_mask);
+       return err_mask;
 }
 
 /**
@@ -2514,11 +2729,11 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
        int dir = qc->dma_dir;
        void *pad_buf = NULL;
 
-       assert(qc->flags & ATA_QCFLAG_DMAMAP);
-       assert(sg != NULL);
+       WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
+       WARN_ON(sg == NULL);
 
        if (qc->flags & ATA_QCFLAG_SINGLE)
-               assert(qc->n_elem <= 1);
+               WARN_ON(qc->n_elem > 1);
 
        VPRINTK("unmapping %u sg elements\n", qc->n_elem);
 
@@ -2573,8 +2788,8 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
        struct scatterlist *sg;
        unsigned int idx;
 
-       assert(qc->__sg != NULL);
-       assert(qc->n_elem > 0 || qc->pad_len > 0);
+       WARN_ON(qc->__sg == NULL);
+       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
 
        idx = 0;
        ata_for_each_sg(sg, qc) {
@@ -2727,7 +2942,7 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
                void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
                struct scatterlist *psg = &qc->pad_sgent;
 
-               assert(qc->dev->class == ATA_DEV_ATAPI);
+               WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
 
                memset(pad_buf, 0, ATA_DMA_PAD_SZ);
 
@@ -2791,7 +3006,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
        int n_elem, pre_n_elem, dir, trim_sg = 0;
 
        VPRINTK("ENTER, ata%u\n", ap->id);
-       assert(qc->flags & ATA_QCFLAG_SG);
+       WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
 
        /* we must lengthen transfers to end on a 32-bit boundary */
        qc->pad_len = lsg->length & 3;
@@ -2800,7 +3015,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
                struct scatterlist *psg = &qc->pad_sgent;
                unsigned int offset;
 
-               assert(qc->dev->class == ATA_DEV_ATAPI);
+               WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
 
                memset(pad_buf, 0, ATA_DMA_PAD_SZ);
 
@@ -2876,7 +3091,7 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc)
 }
 
 /**
- *     ata_pio_poll -
+ *     ata_pio_poll - poll using PIO, depending on current state
  *     @ap: the target ata_port
  *
  *     LOCKING:
@@ -2894,7 +3109,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
        unsigned int reg_state = HSM_ST_UNKNOWN;
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       assert(qc != NULL);
+       WARN_ON(qc == NULL);
 
        switch (ap->hsm_task_state) {
        case HSM_ST:
@@ -2915,7 +3130,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
        status = ata_chk_status(ap);
        if (status & ATA_BUSY) {
                if (time_after(jiffies, ap->pio_task_timeout)) {
-                       qc->err_mask |= AC_ERR_ATA_BUS;
+                       qc->err_mask |= AC_ERR_TIMEOUT;
                        ap->hsm_task_state = HSM_ST_TMOUT;
                        return 0;
                }
@@ -2962,7 +3177,7 @@ static int ata_pio_complete (struct ata_port *ap)
        }
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       assert(qc != NULL);
+       WARN_ON(qc == NULL);
 
        drv_stat = ata_wait_idle(ap);
        if (!ata_ok(drv_stat)) {
@@ -2973,7 +3188,7 @@ static int ata_pio_complete (struct ata_port *ap)
 
        ap->hsm_task_state = HSM_ST_IDLE;
 
-       assert(qc->err_mask == 0);
+       WARN_ON(qc->err_mask);
        ata_poll_qc_complete(qc);
 
        /* another command may start at this point */
@@ -2983,7 +3198,7 @@ static int ata_pio_complete (struct ata_port *ap)
 
 
 /**
- *     swap_buf_le16 - swap halves of 16-words in place
+ *     swap_buf_le16 - swap halves of 16-bit words in place
  *     @buf:  Buffer to swap
  *     @buf_words:  Number of 16-bit words in buffer.
  *
@@ -3293,7 +3508,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
 err_out:
        printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
              ap->id, dev->devno);
-       qc->err_mask |= AC_ERR_ATA_BUS;
+       qc->err_mask |= AC_ERR_HSM;
        ap->hsm_task_state = HSM_ST_ERR;
 }
 
@@ -3330,7 +3545,7 @@ static void ata_pio_block(struct ata_port *ap)
        }
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       assert(qc != NULL);
+       WARN_ON(qc == NULL);
 
        /* check error */
        if (status & (ATA_ERR | ATA_DF)) {
@@ -3351,7 +3566,7 @@ static void ata_pio_block(struct ata_port *ap)
        } else {
                /* handle BSY=0, DRQ=0 as error */
                if ((status & ATA_DRQ) == 0) {
-                       qc->err_mask |= AC_ERR_ATA_BUS;
+                       qc->err_mask |= AC_ERR_HSM;
                        ap->hsm_task_state = HSM_ST_ERR;
                        return;
                }
@@ -3365,7 +3580,7 @@ static void ata_pio_error(struct ata_port *ap)
        struct ata_queued_cmd *qc;
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       assert(qc != NULL);
+       WARN_ON(qc == NULL);
 
        if (qc->tf.command != ATA_CMD_PACKET)
                printk(KERN_WARNING "ata%u: PIO error\n", ap->id);
@@ -3373,7 +3588,7 @@ static void ata_pio_error(struct ata_port *ap)
        /* make sure qc->err_mask is available to 
         * know what's wrong and recover
         */
-       assert(qc->err_mask);
+       WARN_ON(qc->err_mask == 0);
 
        ap->hsm_task_state = HSM_ST_IDLE;
 
@@ -3407,16 +3622,88 @@ fsm_start:
                timeout = ata_pio_poll(ap);
                break;
 
-       case HSM_ST_TMOUT:
-       case HSM_ST_ERR:
-               ata_pio_error(ap);
-               return;
+       case HSM_ST_TMOUT:
+       case HSM_ST_ERR:
+               ata_pio_error(ap);
+               return;
+       }
+
+       if (timeout)
+               ata_port_queue_task(ap, ata_pio_task, ap, timeout);
+       else if (!qc_completed)
+               goto fsm_start;
+}
+
+/**
+ *     atapi_packet_task - Write CDB bytes to hardware
+ *     @_data: Port to which ATAPI device is attached.
+ *
+ *     When device has indicated its readiness to accept
+ *     a CDB, this function is called.  Send the CDB.
+ *     If DMA is to be performed, exit immediately.
+ *     Otherwise, we are in polling mode, so poll
+ *     status under operation succeeds or fails.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ */
+
+static void atapi_packet_task(void *_data)
+{
+       struct ata_port *ap = _data;
+       struct ata_queued_cmd *qc;
+       u8 status;
+
+       qc = ata_qc_from_tag(ap, ap->active_tag);
+       WARN_ON(qc == NULL);
+       WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+
+       /* sleep-wait for BSY to clear */
+       DPRINTK("busy wait\n");
+       if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) {
+               qc->err_mask |= AC_ERR_TIMEOUT;
+               goto err_out;
+       }
+
+       /* make sure DRQ is set */
+       status = ata_chk_status(ap);
+       if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
+               qc->err_mask |= AC_ERR_HSM;
+               goto err_out;
+       }
+
+       /* send SCSI cdb */
+       DPRINTK("send cdb\n");
+       WARN_ON(qc->dev->cdb_len < 12);
+
+       if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
+           qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
+               unsigned long flags;
+
+               /* Once we're done issuing command and kicking bmdma,
+                * irq handler takes over.  To not lose irq, we need
+                * to clear NOINTR flag before sending cdb, but
+                * interrupt handler shouldn't be invoked before we're
+                * finished.  Hence, the following locking.
+                */
+               spin_lock_irqsave(&ap->host_set->lock, flags);
+               ap->flags &= ~ATA_FLAG_NOINTR;
+               ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
+               if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
+                       ap->ops->bmdma_start(qc);       /* initiate bmdma */
+               spin_unlock_irqrestore(&ap->host_set->lock, flags);
+       } else {
+               ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
+
+               /* PIO commands are handled by polling */
+               ap->hsm_task_state = HSM_ST;
+               ata_port_queue_task(ap, ata_pio_task, ap, 0);
        }
 
-       if (timeout)
-               queue_delayed_work(ata_wq, &ap->pio_task, timeout);
-       else if (!qc_completed)
-               goto fsm_start;
+       return;
+
+err_out:
+       ata_poll_qc_complete(qc);
 }
 
 /**
@@ -3447,15 +3734,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
 
        DPRINTK("ENTER\n");
 
-       spin_lock_irqsave(&host_set->lock, flags);
+       ap->hsm_task_state = HSM_ST_IDLE;
 
-       /* hack alert!  We cannot use the supplied completion
-        * function from inside the ->eh_strategy_handler() thread.
-        * libata is the only user of ->eh_strategy_handler() in
-        * any kernel, so the default scsi_done() assumes it is
-        * not being called from the SCSI EH.
-        */
-       qc->scsidone = scsi_finish_command;
+       spin_lock_irqsave(&host_set->lock, flags);
 
        switch (qc->tf.protocol) {
 
@@ -3480,12 +3761,13 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
 
                /* complete taskfile transaction */
                qc->err_mask |= ac_err_mask(drv_stat);
-               ata_qc_complete(qc);
                break;
        }
 
        spin_unlock_irqrestore(&host_set->lock, flags);
 
+       ata_eh_qc_complete(qc);
+
        DPRINTK("EXIT\n");
 }
 
@@ -3510,20 +3792,10 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
 
 void ata_eng_timeout(struct ata_port *ap)
 {
-       struct ata_queued_cmd *qc;
-
        DPRINTK("ENTER\n");
 
-       qc = ata_qc_from_tag(ap, ap->active_tag);
-       if (qc)
-               ata_qc_timeout(qc);
-       else {
-               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-                      ap->id);
-               goto out;
-       }
+       ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
 
-out:
        DPRINTK("EXIT\n");
 }
 
@@ -3579,21 +3851,6 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
        return qc;
 }
 
-static void __ata_qc_complete(struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-       unsigned int tag;
-
-       qc->flags = 0;
-       tag = qc->tag;
-       if (likely(ata_tag_valid(tag))) {
-               if (tag == ap->active_tag)
-                       ap->active_tag = ATA_TAG_POISON;
-               qc->tag = ATA_TAG_POISON;
-               clear_bit(tag, &ap->qactive);
-       }
-}
-
 /**
  *     ata_qc_free - free unused ata_queued_cmd
  *     @qc: Command to complete
@@ -3606,29 +3863,25 @@ static void __ata_qc_complete(struct ata_queued_cmd *qc)
  */
 void ata_qc_free(struct ata_queued_cmd *qc)
 {
-       assert(qc != NULL);     /* ata_qc_from_tag _might_ return NULL */
+       struct ata_port *ap = qc->ap;
+       unsigned int tag;
 
-       __ata_qc_complete(qc);
-}
+       WARN_ON(qc == NULL);    /* ata_qc_from_tag _might_ return NULL */
 
-/**
- *     ata_qc_complete - Complete an active ATA command
- *     @qc: Command to complete
- *     @err_mask: ATA Status register contents
- *
- *     Indicate to the mid and upper layers that an ATA
- *     command has completed, with either an ok or not-ok status.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
- */
+       qc->flags = 0;
+       tag = qc->tag;
+       if (likely(ata_tag_valid(tag))) {
+               if (tag == ap->active_tag)
+                       ap->active_tag = ATA_TAG_POISON;
+               qc->tag = ATA_TAG_POISON;
+               clear_bit(tag, &ap->qactive);
+       }
+}
 
-void ata_qc_complete(struct ata_queued_cmd *qc)
+void __ata_qc_complete(struct ata_queued_cmd *qc)
 {
-       int rc;
-
-       assert(qc != NULL);     /* ata_qc_from_tag _might_ return NULL */
-       assert(qc->flags & ATA_QCFLAG_ACTIVE);
+       WARN_ON(qc == NULL);    /* ata_qc_from_tag _might_ return NULL */
+       WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
 
        if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
                ata_sg_clean(qc);
@@ -3640,17 +3893,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
        qc->flags &= ~ATA_QCFLAG_ACTIVE;
 
        /* call completion callback */
-       rc = qc->complete_fn(qc);
-
-       /* if callback indicates not to complete command (non-zero),
-        * return immediately
-        */
-       if (rc != 0)
-               return;
-
-       __ata_qc_complete(qc);
-
-       VPRINTK("EXIT\n");
+       qc->complete_fn(qc);
 }
 
 static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
@@ -3690,20 +3933,20 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
  *     spin_lock_irqsave(host_set lock)
  *
  *     RETURNS:
- *     Zero on success, negative on error.
+ *     Zero on success, AC_ERR_* mask on failure
  */
 
-int ata_qc_issue(struct ata_queued_cmd *qc)
+unsigned int ata_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
 
        if (ata_should_dma_map(qc)) {
                if (qc->flags & ATA_QCFLAG_SG) {
                        if (ata_sg_setup(qc))
-                               goto err_out;
+                               goto sg_err;
                } else if (qc->flags & ATA_QCFLAG_SINGLE) {
                        if (ata_sg_setup_one(qc))
-                               goto err_out;
+                               goto sg_err;
                }
        } else {
                qc->flags &= ~ATA_QCFLAG_DMAMAP;
@@ -3716,8 +3959,9 @@ int ata_qc_issue(struct ata_queued_cmd *qc)
 
        return ap->ops->qc_issue(qc);
 
-err_out:
-       return -1;
+sg_err:
+       qc->flags &= ~ATA_QCFLAG_DMAMAP;
+       return AC_ERR_SYSTEM;
 }
 
 
@@ -3736,10 +3980,10 @@ err_out:
  *     spin_lock_irqsave(host_set lock)
  *
  *     RETURNS:
- *     Zero on success, negative on error.
+ *     Zero on success, AC_ERR_* mask on failure
  */
 
-int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
 
@@ -3760,31 +4004,31 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc)
                ata_qc_set_polling(qc);
                ata_tf_to_host(ap, &qc->tf);
                ap->hsm_task_state = HSM_ST;
-               queue_work(ata_wq, &ap->pio_task);
+               ata_port_queue_task(ap, ata_pio_task, ap, 0);
                break;
 
        case ATA_PROT_ATAPI:
                ata_qc_set_polling(qc);
                ata_tf_to_host(ap, &qc->tf);
-               queue_work(ata_wq, &ap->packet_task);
+               ata_port_queue_task(ap, atapi_packet_task, ap, 0);
                break;
 
        case ATA_PROT_ATAPI_NODATA:
                ap->flags |= ATA_FLAG_NOINTR;
                ata_tf_to_host(ap, &qc->tf);
-               queue_work(ata_wq, &ap->packet_task);
+               ata_port_queue_task(ap, atapi_packet_task, ap, 0);
                break;
 
        case ATA_PROT_ATAPI_DMA:
                ap->flags |= ATA_FLAG_NOINTR;
                ap->ops->tf_load(ap, &qc->tf);   /* load tf registers */
                ap->ops->bmdma_setup(qc);           /* set up bmdma */
-               queue_work(ata_wq, &ap->packet_task);
+               ata_port_queue_task(ap, atapi_packet_task, ap, 0);
                break;
 
        default:
                WARN_ON(1);
-               return -1;
+               return AC_ERR_SYSTEM;
        }
 
        return 0;
@@ -4147,91 +4391,6 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
        return IRQ_RETVAL(handled);
 }
 
-/**
- *     atapi_packet_task - Write CDB bytes to hardware
- *     @_data: Port to which ATAPI device is attached.
- *
- *     When device has indicated its readiness to accept
- *     a CDB, this function is called.  Send the CDB.
- *     If DMA is to be performed, exit immediately.
- *     Otherwise, we are in polling mode, so poll
- *     status under operation succeeds or fails.
- *
- *     LOCKING:
- *     Kernel thread context (may sleep)
- */
-
-static void atapi_packet_task(void *_data)
-{
-       struct ata_port *ap = _data;
-       struct ata_queued_cmd *qc;
-       u8 status;
-
-       qc = ata_qc_from_tag(ap, ap->active_tag);
-       assert(qc != NULL);
-       assert(qc->flags & ATA_QCFLAG_ACTIVE);
-
-       /* sleep-wait for BSY to clear */
-       DPRINTK("busy wait\n");
-       if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) {
-               qc->err_mask |= AC_ERR_ATA_BUS;
-               goto err_out;
-       }
-
-       /* make sure DRQ is set */
-       status = ata_chk_status(ap);
-       if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) {
-               qc->err_mask |= AC_ERR_ATA_BUS;
-               goto err_out;
-       }
-
-       /* send SCSI cdb */
-       DPRINTK("send cdb\n");
-       assert(ap->cdb_len >= 12);
-
-       if (qc->tf.protocol == ATA_PROT_ATAPI_DMA ||
-           qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
-               unsigned long flags;
-
-               /* Once we're done issuing command and kicking bmdma,
-                * irq handler takes over.  To not lose irq, we need
-                * to clear NOINTR flag before sending cdb, but
-                * interrupt handler shouldn't be invoked before we're
-                * finished.  Hence, the following locking.
-                */
-               spin_lock_irqsave(&ap->host_set->lock, flags);
-               ap->flags &= ~ATA_FLAG_NOINTR;
-               ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
-               if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
-                       ap->ops->bmdma_start(qc);       /* initiate bmdma */
-               spin_unlock_irqrestore(&ap->host_set->lock, flags);
-       } else {
-               ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
-
-               /* PIO commands are handled by polling */
-               ap->hsm_task_state = HSM_ST;
-               queue_work(ata_wq, &ap->pio_task);
-       }
-
-       return;
-
-err_out:
-       ata_poll_qc_complete(qc);
-}
-
-
-/**
- *     ata_port_start - Set port up for dma.
- *     @ap: Port to initialize
- *
- *     Called just after data structures for each port are
- *     initialized.  Allocates space for PRD table.
- *
- *     May be used as the port_start() entry in ata_port_operations.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
 
 /*
  * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
@@ -4284,6 +4443,8 @@ static int ata_start_drive(struct ata_port *ap, struct ata_device *dev)
 
 /**
  *     ata_device_resume - wakeup a previously suspended devices
+ *     @ap: port the device is connected to
+ *     @dev: the device to resume
  *
  *     Kick the drive back into action, by sending it an idle immediate
  *     command and making sure its transfer mode matches between drive
@@ -4306,10 +4467,11 @@ int ata_device_resume(struct ata_port *ap, struct ata_device *dev)
 
 /**
  *     ata_device_suspend - prepare a device for suspend
+ *     @ap: port the device is connected to
+ *     @dev: the device to suspend
  *
  *     Flush the cache on the drive, if appropriate, then issue a
  *     standbynow command.
- *
  */
 int ata_device_suspend(struct ata_port *ap, struct ata_device *dev)
 {
@@ -4323,6 +4485,19 @@ int ata_device_suspend(struct ata_port *ap, struct ata_device *dev)
        return 0;
 }
 
+/**
+ *     ata_port_start - Set port up for dma.
+ *     @ap: Port to initialize
+ *
+ *     Called just after data structures for each port are
+ *     initialized.  Allocates space for PRD table.
+ *
+ *     May be used as the port_start() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
 int ata_port_start (struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
@@ -4436,8 +4611,8 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
        ap->active_tag = ATA_TAG_POISON;
        ap->last_ctl = 0xFF;
 
-       INIT_WORK(&ap->packet_task, atapi_packet_task, ap);
-       INIT_WORK(&ap->pio_task, ata_pio_task, ap);
+       INIT_WORK(&ap->port_task, NULL, NULL);
+       INIT_LIST_HEAD(&ap->eh_done_q);
 
        for (i = 0; i < ATA_MAX_DEVICES; i++)
                ap->device[i].devno = i;
@@ -4579,9 +4754,9 @@ int ata_device_add(const struct ata_probe_ent *ent)
 
                ap = host_set->ports[i];
 
-               DPRINTK("ata%u: probe begin\n", ap->id);
+               DPRINTK("ata%u: bus probe begin\n", ap->id);
                rc = ata_bus_probe(ap);
-               DPRINTK("ata%u: probe end\n", ap->id);
+               DPRINTK("ata%u: bus probe end\n", ap->id);
 
                if (rc) {
                        /* FIXME: do something useful here?
@@ -4605,7 +4780,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
        }
 
        /* probes are done, now scan each port's disk(s) */
-       DPRINTK("probe begin\n");
+       DPRINTK("host probe begin\n");
        for (i = 0; i < count; i++) {
                struct ata_port *ap = host_set->ports[i];
 
@@ -4691,11 +4866,14 @@ void ata_host_set_remove(struct ata_host_set *host_set)
 int ata_scsi_release(struct Scsi_Host *host)
 {
        struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+       int i;
 
        DPRINTK("ENTER\n");
 
        ap->ops->port_disable(ap);
        ata_host_remove(ap, 0);
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               kfree(ap->device[i].id);
 
        DPRINTK("EXIT\n");
        return 1;
@@ -4727,32 +4905,6 @@ void ata_std_ports(struct ata_ioports *ioaddr)
        ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
 }
 
-static struct ata_probe_ent *
-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
-{
-       struct ata_probe_ent *probe_ent;
-
-       probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
-       if (!probe_ent) {
-               printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
-                      kobject_name(&(dev->kobj)));
-               return NULL;
-       }
-
-       INIT_LIST_HEAD(&probe_ent->node);
-       probe_ent->dev = dev;
-
-       probe_ent->sht = port->sht;
-       probe_ent->host_flags = port->host_flags;
-       probe_ent->pio_mask = port->pio_mask;
-       probe_ent->mwdma_mask = port->mwdma_mask;
-       probe_ent->udma_mask = port->udma_mask;
-       probe_ent->port_ops = port->port_ops;
-
-       return probe_ent;
-}
-
-
 
 #ifdef CONFIG_PCI
 
@@ -4764,256 +4916,6 @@ void ata_pci_host_stop (struct ata_host_set *host_set)
 }
 
 /**
- *     ata_pci_init_native_mode - Initialize native-mode driver
- *     @pdev:  pci device to be initialized
- *     @port:  array[2] of pointers to port info structures.
- *     @ports: bitmap of ports present
- *
- *     Utility function which allocates and initializes an
- *     ata_probe_ent structure for a standard dual-port
- *     PIO-based IDE controller.  The returned ata_probe_ent
- *     structure can be passed to ata_device_add().  The returned
- *     ata_probe_ent structure should then be freed with kfree().
- *
- *     The caller need only pass the address of the primary port, the
- *     secondary will be deduced automatically. If the device has non
- *     standard secondary port mappings this function can be called twice,
- *     once for each interface.
- */
-
-struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
-{
-       struct ata_probe_ent *probe_ent =
-               ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
-       int p = 0;
-
-       if (!probe_ent)
-               return NULL;
-
-       probe_ent->irq = pdev->irq;
-       probe_ent->irq_flags = SA_SHIRQ;
-       probe_ent->private_data = port[0]->private_data;
-
-       if (ports & ATA_PORT_PRIMARY) {
-               probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
-               probe_ent->port[p].altstatus_addr =
-               probe_ent->port[p].ctl_addr =
-                       pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
-               probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
-               ata_std_ports(&probe_ent->port[p]);
-               p++;
-       }
-
-       if (ports & ATA_PORT_SECONDARY) {
-               probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
-               probe_ent->port[p].altstatus_addr =
-               probe_ent->port[p].ctl_addr =
-                       pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
-               probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
-               ata_std_ports(&probe_ent->port[p]);
-               p++;
-       }
-
-       probe_ent->n_ports = p;
-       return probe_ent;
-}
-
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info *port, int port_num)
-{
-       struct ata_probe_ent *probe_ent;
-
-       probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
-       if (!probe_ent)
-               return NULL;
-
-       probe_ent->legacy_mode = 1;
-       probe_ent->n_ports = 1;
-       probe_ent->hard_port_no = port_num;
-       probe_ent->private_data = port->private_data;
-
-       switch(port_num)
-       {
-               case 0:
-                       probe_ent->irq = 14;
-                       probe_ent->port[0].cmd_addr = 0x1f0;
-                       probe_ent->port[0].altstatus_addr =
-                       probe_ent->port[0].ctl_addr = 0x3f6;
-                       break;
-               case 1:
-                       probe_ent->irq = 15;
-                       probe_ent->port[0].cmd_addr = 0x170;
-                       probe_ent->port[0].altstatus_addr =
-                       probe_ent->port[0].ctl_addr = 0x376;
-                       break;
-       }
-       probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num;
-       ata_std_ports(&probe_ent->port[0]);
-       return probe_ent;
-}
-
-/**
- *     ata_pci_init_one - Initialize/register PCI IDE host controller
- *     @pdev: Controller to be initialized
- *     @port_info: Information from low-level host driver
- *     @n_ports: Number of ports attached to host controller
- *
- *     This is a helper function which can be called from a driver's
- *     xxx_init_one() probe function if the hardware uses traditional
- *     IDE taskfile registers.
- *
- *     This function calls pci_enable_device(), reserves its register
- *     regions, sets the dma mask, enables bus master mode, and calls
- *     ata_device_add()
- *
- *     LOCKING:
- *     Inherited from PCI layer (may sleep).
- *
- *     RETURNS:
- *     Zero on success, negative on errno-based value on error.
- */
-
-int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
-                     unsigned int n_ports)
-{
-       struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
-       struct ata_port_info *port[2];
-       u8 tmp8, mask;
-       unsigned int legacy_mode = 0;
-       int disable_dev_on_err = 1;
-       int rc;
-
-       DPRINTK("ENTER\n");
-
-       port[0] = port_info[0];
-       if (n_ports > 1)
-               port[1] = port_info[1];
-       else
-               port[1] = port[0];
-
-       if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
-           && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-               /* TODO: What if one channel is in native mode ... */
-               pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
-               mask = (1 << 2) | (1 << 0);
-               if ((tmp8 & mask) != mask)
-                       legacy_mode = (1 << 3);
-       }
-
-       /* FIXME... */
-       if ((!legacy_mode) && (n_ports > 2)) {
-               printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
-               n_ports = 2;
-               /* For now */
-       }
-
-       /* FIXME: Really for ATA it isn't safe because the device may be
-          multi-purpose and we want to leave it alone if it was already
-          enabled. Secondly for shared use as Arjan says we want refcounting
-          
-          Checking dev->is_enabled is insufficient as this is not set at
-          boot for the primary video which is BIOS enabled
-         */
-         
-       rc = pci_enable_device(pdev);
-       if (rc)
-               return rc;
-
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc) {
-               disable_dev_on_err = 0;
-               goto err_out;
-       }
-
-       /* FIXME: Should use platform specific mappers for legacy port ranges */
-       if (legacy_mode) {
-               if (!request_region(0x1f0, 8, "libata")) {
-                       struct resource *conflict, res;
-                       res.start = 0x1f0;
-                       res.end = 0x1f0 + 8 - 1;
-                       conflict = ____request_resource(&ioport_resource, &res);
-                       if (!strcmp(conflict->name, "libata"))
-                               legacy_mode |= (1 << 0);
-                       else {
-                               disable_dev_on_err = 0;
-                               printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
-                       }
-               } else
-                       legacy_mode |= (1 << 0);
-
-               if (!request_region(0x170, 8, "libata")) {
-                       struct resource *conflict, res;
-                       res.start = 0x170;
-                       res.end = 0x170 + 8 - 1;
-                       conflict = ____request_resource(&ioport_resource, &res);
-                       if (!strcmp(conflict->name, "libata"))
-                               legacy_mode |= (1 << 1);
-                       else {
-                               disable_dev_on_err = 0;
-                               printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
-                       }
-               } else
-                       legacy_mode |= (1 << 1);
-       }
-
-       /* we have legacy mode, but all ports are unavailable */
-       if (legacy_mode == (1 << 3)) {
-               rc = -EBUSY;
-               goto err_out_regions;
-       }
-
-       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               goto err_out_regions;
-       rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-       if (rc)
-               goto err_out_regions;
-
-       if (legacy_mode) {
-               if (legacy_mode & (1 << 0))
-                       probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
-               if (legacy_mode & (1 << 1))
-                       probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
-       } else {
-               if (n_ports == 2)
-                       probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-               else
-                       probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
-       }
-       if (!probe_ent && !probe_ent2) {
-               rc = -ENOMEM;
-               goto err_out_regions;
-       }
-
-       pci_set_master(pdev);
-
-       /* FIXME: check ata_device_add return */
-       if (legacy_mode) {
-               if (legacy_mode & (1 << 0))
-                       ata_device_add(probe_ent);
-               if (legacy_mode & (1 << 1))
-                       ata_device_add(probe_ent2);
-       } else
-               ata_device_add(probe_ent);
-
-       kfree(probe_ent);
-       kfree(probe_ent2);
-
-       return 0;
-
-err_out_regions:
-       if (legacy_mode & (1 << 0))
-               release_region(0x1f0, 8);
-       if (legacy_mode & (1 << 1))
-               release_region(0x170, 8);
-       pci_release_regions(pdev);
-err_out:
-       if (disable_dev_on_err)
-               pci_disable_device(pdev);
-       return rc;
-}
-
-/**
  *     ata_pci_remove_one - PCI layer callback for device removal
  *     @pdev: PCI device that was removed
  *
@@ -5143,7 +5045,7 @@ EXPORT_SYMBOL_GPL(ata_device_add);
 EXPORT_SYMBOL_GPL(ata_host_set_remove);
 EXPORT_SYMBOL_GPL(ata_sg_init);
 EXPORT_SYMBOL_GPL(ata_sg_init_one);
-EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(__ata_qc_complete);
 EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_tf_load);
@@ -5169,18 +5071,30 @@ EXPORT_SYMBOL_GPL(ata_port_probe);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
+EXPORT_SYMBOL_GPL(ata_std_probeinit);
+EXPORT_SYMBOL_GPL(ata_std_softreset);
+EXPORT_SYMBOL_GPL(sata_std_hardreset);
+EXPORT_SYMBOL_GPL(ata_std_postreset);
+EXPORT_SYMBOL_GPL(ata_std_probe_reset);
+EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
+EXPORT_SYMBOL_GPL(ata_dev_revalidate);
 EXPORT_SYMBOL_GPL(ata_port_disable);
 EXPORT_SYMBOL_GPL(ata_ratelimit);
+EXPORT_SYMBOL_GPL(ata_busy_sleep);
+EXPORT_SYMBOL_GPL(ata_port_queue_task);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
+EXPORT_SYMBOL_GPL(ata_scsi_timed_out);
 EXPORT_SYMBOL_GPL(ata_scsi_error);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
 EXPORT_SYMBOL_GPL(ata_scsi_release);
 EXPORT_SYMBOL_GPL(ata_host_intr);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
-EXPORT_SYMBOL_GPL(ata_dev_id_string);
-EXPORT_SYMBOL_GPL(ata_dev_config);
+EXPORT_SYMBOL_GPL(ata_id_string);
+EXPORT_SYMBOL_GPL(ata_id_c_string);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
+EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
+EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
 
 EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
 EXPORT_SYMBOL_GPL(ata_timing_compute);
index 59503c9..ccedb45 100644 (file)
@@ -151,7 +151,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
        struct scsi_sense_hdr sshdr;
        enum dma_data_direction data_dir;
 
-       if (NULL == (void *)arg)
+       if (arg == NULL)
                return -EINVAL;
 
        if (copy_from_user(args, arg, sizeof(args)))
@@ -201,7 +201,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
        /* Need code to retrieve data from check condition? */
 
        if ((argbuf)
-        && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize))
+        && copy_to_user(arg + sizeof(args), argbuf, argsize))
                rc = -EFAULT;
 error:
        if (argbuf)
@@ -228,7 +228,7 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
        u8 args[7];
        struct scsi_sense_hdr sshdr;
 
-       if (NULL == (void *)arg)
+       if (arg == NULL)
                return -EINVAL;
 
        if (copy_from_user(args, arg, sizeof(args)))
@@ -553,7 +553,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
        /*
         * Read the controller registers.
         */
-       assert(NULL != qc->ap->ops->tf_read);
+       WARN_ON(qc->ap->ops->tf_read == NULL);
        qc->ap->ops->tf_read(qc->ap, tf);
 
        /*
@@ -628,7 +628,7 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
        /*
         * Read the controller registers.
         */
-       assert(NULL != qc->ap->ops->tf_read);
+       WARN_ON(qc->ap->ops->tf_read == NULL);
        qc->ap->ops->tf_read(qc->ap, tf);
 
        /*
@@ -684,23 +684,23 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
        if (sdev->id < ATA_MAX_DEVICES) {
                struct ata_port *ap;
                struct ata_device *dev;
+               unsigned int max_sectors;
 
                ap = (struct ata_port *) &sdev->host->hostdata[0];
                dev = &ap->device[sdev->id];
 
-               /* TODO: 1024 is an arbitrary number, not the
+               /* TODO: 2048 is an arbitrary number, not the
                 * hardware maximum.  This should be increased to
                 * 65534 when Jens Axboe's patch for dynamically
                 * determining max_sectors is merged.
                 */
-               if ((dev->flags & ATA_DFLAG_LBA48) &&
-                   ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) {
-                       /*
-                        * do not overwrite sdev->host->max_sectors, since
-                        * other drives on this host may not support LBA48
-                        */
-                       blk_queue_max_sectors(sdev->request_queue, 2048);
-               }
+               max_sectors = ATA_MAX_SECTORS;
+               if (dev->flags & ATA_DFLAG_LBA48)
+                       max_sectors = 2048;
+               if (dev->max_sectors)
+                       max_sectors = dev->max_sectors;
+
+               blk_queue_max_sectors(sdev->request_queue, max_sectors);
 
                /*
                 * SATA DMA transfers must be multiples of 4 byte, so
@@ -717,6 +717,47 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
 }
 
 /**
+ *     ata_scsi_timed_out - SCSI layer time out callback
+ *     @cmd: timed out SCSI command
+ *
+ *     Handles SCSI layer timeout.  We race with normal completion of
+ *     the qc for @cmd.  If the qc is already gone, we lose and let
+ *     the scsi command finish (EH_HANDLED).  Otherwise, the qc has
+ *     timed out and EH should be invoked.  Prevent ata_qc_complete()
+ *     from finishing it by setting EH_SCHEDULED and return
+ *     EH_NOT_HANDLED.
+ *
+ *     LOCKING:
+ *     Called from timer context
+ *
+ *     RETURNS:
+ *     EH_HANDLED or EH_NOT_HANDLED
+ */
+enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+       struct Scsi_Host *host = cmd->device->host;
+       struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+       unsigned long flags;
+       struct ata_queued_cmd *qc;
+       enum scsi_eh_timer_return ret = EH_HANDLED;
+
+       DPRINTK("ENTER\n");
+
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       qc = ata_qc_from_tag(ap, ap->active_tag);
+       if (qc) {
+               WARN_ON(qc->scsicmd != cmd);
+               qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
+               qc->err_mask |= AC_ERR_TIMEOUT;
+               ret = EH_NOT_HANDLED;
+       }
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+       DPRINTK("EXIT, ret=%d\n", ret);
+       return ret;
+}
+
+/**
  *     ata_scsi_error - SCSI layer error handler callback
  *     @host: SCSI host on which error occurred
  *
@@ -732,23 +773,84 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
 int ata_scsi_error(struct Scsi_Host *host)
 {
        struct ata_port *ap;
+       unsigned long flags;
 
        DPRINTK("ENTER\n");
 
        ap = (struct ata_port *) &host->hostdata[0];
+
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       WARN_ON(ap->flags & ATA_FLAG_IN_EH);
+       ap->flags |= ATA_FLAG_IN_EH;
+       WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+       ata_port_flush_task(ap);
+
        ap->ops->eng_timeout(ap);
 
-       /* TODO: this is per-command; when queueing is supported
-        * this code will either change or move to a more
-        * appropriate place
-        */
-       host->host_failed--;
-       INIT_LIST_HEAD(&host->eh_cmd_q);
+       WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
+
+       scsi_eh_flush_done_q(&ap->eh_done_q);
+
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       ap->flags &= ~ATA_FLAG_IN_EH;
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
        DPRINTK("EXIT\n");
        return 0;
 }
 
+static void ata_eh_scsidone(struct scsi_cmnd *scmd)
+{
+       /* nada */
+}
+
+static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct scsi_cmnd *scmd = qc->scsicmd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       qc->scsidone = ata_eh_scsidone;
+       __ata_qc_complete(qc);
+       WARN_ON(ata_tag_valid(qc->tag));
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+       scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+}
+
+/**
+ *     ata_eh_qc_complete - Complete an active ATA command from EH
+ *     @qc: Command to complete
+ *
+ *     Indicate to the mid and upper layers that an ATA command has
+ *     completed.  To be used from EH.
+ */
+void ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+       struct scsi_cmnd *scmd = qc->scsicmd;
+       scmd->retries = scmd->allowed;
+       __ata_eh_qc_complete(qc);
+}
+
+/**
+ *     ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
+ *     @qc: Command to retry
+ *
+ *     Indicate to the mid and upper layers that an ATA command
+ *     should be retried.  To be used from EH.
+ *
+ *     SCSI midlayer limits the number of retries to scmd->allowed.
+ *     This function might need to adjust scmd->retries for commands
+ *     which get retried due to unrelated NCQ failures.
+ */
+void ata_eh_qc_retry(struct ata_queued_cmd *qc)
+{
+       __ata_eh_qc_complete(qc);
+}
+
 /**
  *     ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
  *     @qc: Storage for translated ATA taskfile
@@ -985,9 +1087,13 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
        if (dev->flags & ATA_DFLAG_LBA) {
                tf->flags |= ATA_TFLAG_LBA;
 
-               if (dev->flags & ATA_DFLAG_LBA48) {
-                       if (n_block > (64 * 1024))
-                               goto invalid_fld;
+               if (lba_28_ok(block, n_block)) {
+                       /* use LBA28 */
+                       tf->command = ATA_CMD_VERIFY;
+                       tf->device |= (block >> 24) & 0xf;
+               } else if (lba_48_ok(block, n_block)) {
+                       if (!(dev->flags & ATA_DFLAG_LBA48))
+                               goto out_of_range;
 
                        /* use LBA48 */
                        tf->flags |= ATA_TFLAG_LBA48;
@@ -998,15 +1104,9 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
                        tf->hob_lbah = (block >> 40) & 0xff;
                        tf->hob_lbam = (block >> 32) & 0xff;
                        tf->hob_lbal = (block >> 24) & 0xff;
-               } else {
-                       if (n_block > 256)
-                               goto invalid_fld;
-
-                       /* use LBA28 */
-                       tf->command = ATA_CMD_VERIFY;
-
-                       tf->device |= (block >> 24) & 0xf;
-               }
+               } else
+                       /* request too large even for LBA48 */
+                       goto out_of_range;
 
                tf->nsect = n_block & 0xff;
 
@@ -1019,8 +1119,8 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *sc
                /* CHS */
                u32 sect, head, cyl, track;
 
-               if (n_block > 256)
-                       goto invalid_fld;
+               if (!lba_28_ok(block, n_block))
+                       goto out_of_range;
 
                /* Convert LBA to CHS */
                track = (u32)block / dev->sectors;
@@ -1139,9 +1239,11 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
        if (dev->flags & ATA_DFLAG_LBA) {
                tf->flags |= ATA_TFLAG_LBA;
 
-               if (dev->flags & ATA_DFLAG_LBA48) {
-                       /* The request -may- be too large for LBA48. */
-                       if ((block >> 48) || (n_block > 65536))
+               if (lba_28_ok(block, n_block)) {
+                       /* use LBA28 */
+                       tf->device |= (block >> 24) & 0xf;
+               } else if (lba_48_ok(block, n_block)) {
+                       if (!(dev->flags & ATA_DFLAG_LBA48))
                                goto out_of_range;
 
                        /* use LBA48 */
@@ -1152,15 +1254,9 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
                        tf->hob_lbah = (block >> 40) & 0xff;
                        tf->hob_lbam = (block >> 32) & 0xff;
                        tf->hob_lbal = (block >> 24) & 0xff;
-               } else { 
-                       /* use LBA28 */
-
-                       /* The request -may- be too large for LBA28. */
-                       if ((block >> 28) || (n_block > 256))
-                               goto out_of_range;
-
-                       tf->device |= (block >> 24) & 0xf;
-               }
+               } else
+                       /* request too large even for LBA48 */
+                       goto out_of_range;
 
                if (unlikely(ata_rwcmd_protocol(qc) < 0))
                        goto invalid_fld;
@@ -1178,7 +1274,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
                u32 sect, head, cyl, track;
 
                /* The request -may- be too large for CHS addressing. */
-               if ((block >> 28) || (n_block > 256))
+               if (!lba_28_ok(block, n_block))
                        goto out_of_range;
 
                if (unlikely(ata_rwcmd_protocol(qc) < 0))
@@ -1225,7 +1321,7 @@ nothing_to_do:
        return 1;
 }
 
-static int ata_scsi_qc_complete(struct ata_queued_cmd *qc)
+static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
 {
        struct scsi_cmnd *cmd = qc->scsicmd;
        u8 *cdb = cmd->cmnd;
@@ -1262,7 +1358,7 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc)
 
        qc->scsidone(cmd);
 
-       return 0;
+       ata_qc_free(qc);
 }
 
 /**
@@ -1328,8 +1424,9 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
                goto early_finish;
 
        /* select device, send command to hardware */
-       if (ata_qc_issue(qc))
-               goto err_did;
+       qc->err_mask = ata_qc_issue(qc);
+       if (qc->err_mask)
+               ata_qc_complete(qc);
 
        VPRINTK("EXIT\n");
        return;
@@ -1472,8 +1569,8 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
 
        if (buflen > 35) {
                memcpy(&rbuf[8], "ATA     ", 8);
-               ata_dev_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
-               ata_dev_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
+               ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
+               ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
                if (rbuf[32] == 0 || rbuf[32] == ' ')
                        memcpy(&rbuf[32], "n/a ", 4);
        }
@@ -1547,8 +1644,8 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
        memcpy(rbuf, hdr, sizeof(hdr));
 
        if (buflen > (ATA_SERNO_LEN + 4 - 1))
-               ata_dev_id_string(args->id, (unsigned char *) &rbuf[4],
-                                 ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+               ata_id_string(args->id, (unsigned char *) &rbuf[4],
+                             ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
 
        return 0;
 }
@@ -1713,15 +1810,12 @@ static int ata_dev_supports_fua(u16 *id)
        if (!ata_id_has_fua(id))
                return 0;
 
-       model[40] = '\0';
-       fw[8] = '\0';
-
-       ata_dev_id_string(id, model, ATA_ID_PROD_OFS, sizeof(model) - 1);
-       ata_dev_id_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw) - 1);
+       ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
+       ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
 
-       if (strncmp(model, "Maxtor", 6))
+       if (strcmp(model, "Maxtor"))
                return 1;
-       if (strncmp(fw, "BANC1G10", 8))
+       if (strcmp(fw, "BANC1G10"))
                return 1;
 
        return 0; /* blacklisted */
@@ -2015,7 +2109,7 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8
        done(cmd);
 }
 
-static int atapi_sense_complete(struct ata_queued_cmd *qc)
+static void atapi_sense_complete(struct ata_queued_cmd *qc)
 {
        if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0))
                /* FIXME: not quite right; we don't want the
@@ -2026,7 +2120,7 @@ static int atapi_sense_complete(struct ata_queued_cmd *qc)
                ata_gen_ata_desc_sense(qc);
 
        qc->scsidone(qc->scsicmd);
-       return 0;
+       ata_qc_free(qc);
 }
 
 /* is it pointless to prefer PIO for "safety reasons"? */
@@ -2056,7 +2150,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
        ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
        qc->dma_dir = DMA_FROM_DEVICE;
 
-       memset(&qc->cdb, 0, ap->cdb_len);
+       memset(&qc->cdb, 0, qc->dev->cdb_len);
        qc->cdb[0] = REQUEST_SENSE;
        qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
 
@@ -2075,15 +2169,14 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
 
        qc->complete_fn = atapi_sense_complete;
 
-       if (ata_qc_issue(qc)) {
-               qc->err_mask |= AC_ERR_OTHER;
+       qc->err_mask = ata_qc_issue(qc);
+       if (qc->err_mask)
                ata_qc_complete(qc);
-       }
 
        DPRINTK("EXIT\n");
 }
 
-static int atapi_qc_complete(struct ata_queued_cmd *qc)
+static void atapi_qc_complete(struct ata_queued_cmd *qc)
 {
        struct scsi_cmnd *cmd = qc->scsicmd;
        unsigned int err_mask = qc->err_mask;
@@ -2093,7 +2186,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc)
        if (unlikely(err_mask & AC_ERR_DEV)) {
                cmd->result = SAM_STAT_CHECK_CONDITION;
                atapi_request_sense(qc);
-               return 1;
+               return;
        }
 
        else if (unlikely(err_mask))
@@ -2133,7 +2226,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc)
        }
 
        qc->scsidone(cmd);
-       return 0;
+       ata_qc_free(qc);
 }
 /**
  *     atapi_xlat - Initialize PACKET taskfile
@@ -2159,7 +2252,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
                if (ata_check_atapi_dma(qc))
                        using_pio = 1;
 
-       memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
+       memcpy(&qc->cdb, scsicmd, dev->cdb_len);
 
        qc->complete_fn = atapi_qc_complete;
 
@@ -2519,7 +2612,8 @@ out_unlock:
 
 /**
  *     ata_scsi_simulate - simulate SCSI command on ATA device
- *     @id: current IDENTIFY data for target device.
+ *     @ap: port the device is connected to
+ *     @dev: the target device
  *     @cmd: SCSI command being sent to device.
  *     @done: SCSI command completion function.
  *
index fddaf47..f4c48c9 100644 (file)
@@ -45,8 +45,9 @@ extern int libata_fua;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
                                      struct ata_device *dev);
 extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
+extern void ata_port_flush_task(struct ata_port *ap);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
-extern int ata_qc_issue(struct ata_queued_cmd *qc);
+extern unsigned int ata_qc_issue(struct ata_queued_cmd *qc);
 extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
index e8df0c9..5f33cc9 100644 (file)
@@ -131,7 +131,7 @@ static void adma_host_stop(struct ata_host_set *host_set);
 static void adma_port_stop(struct ata_port *ap);
 static void adma_phy_reset(struct ata_port *ap);
 static void adma_qc_prep(struct ata_queued_cmd *qc);
-static int adma_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
 static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void adma_bmdma_stop(struct ata_queued_cmd *qc);
 static u8 adma_bmdma_status(struct ata_port *ap);
@@ -143,11 +143,11 @@ static struct scsi_host_template adma_ata_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ENABLE_CLUSTERING,
@@ -419,7 +419,7 @@ static inline void adma_packet_start(struct ata_queued_cmd *qc)
        writew(aPIOMD4 | aGO, chan + ADMA_CONTROL);
 }
 
-static int adma_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
 {
        struct adma_port_priv *pp = qc->ap->private_data;
 
index 2770005..e561281 100644 (file)
@@ -37,7 +37,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "sata_mv"
-#define DRV_VERSION    "0.5"
+#define DRV_VERSION    "0.6"
 
 enum {
        /* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -228,7 +228,9 @@ enum {
        MV_HP_ERRATA_50XXB2     = (1 << 2),
        MV_HP_ERRATA_60X1B2     = (1 << 3),
        MV_HP_ERRATA_60X1C0     = (1 << 4),
-       MV_HP_50XX              = (1 << 5),
+       MV_HP_ERRATA_XX42A0     = (1 << 5),
+       MV_HP_50XX              = (1 << 6),
+       MV_HP_GEN_IIE           = (1 << 7),
 
        /* Port private flags (pp_flags) */
        MV_PP_FLAG_EDMA_EN      = (1 << 0),
@@ -237,6 +239,9 @@ enum {
 
 #define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
 #define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
+#define IS_GEN_I(hpriv) IS_50XX(hpriv)
+#define IS_GEN_II(hpriv) IS_60XX(hpriv)
+#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
 
 enum {
        /* Our DMA boundary is determined by an ePRD being unable to handle
@@ -255,6 +260,8 @@ enum chip_type {
        chip_5080,
        chip_604x,
        chip_608x,
+       chip_6042,
+       chip_7042,
 };
 
 /* Command ReQuest Block: 32B */
@@ -265,6 +272,14 @@ struct mv_crqb {
        u16                     ata_cmd[11];
 };
 
+struct mv_crqb_iie {
+       u32                     addr;
+       u32                     addr_hi;
+       u32                     flags;
+       u32                     len;
+       u32                     ata_cmd[4];
+};
+
 /* Command ResPonse Block: 8B */
 struct mv_crpb {
        u16                     id;
@@ -328,7 +343,8 @@ static void mv_host_stop(struct ata_host_set *host_set);
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static void mv_qc_prep(struct ata_queued_cmd *qc);
-static int mv_qc_issue(struct ata_queued_cmd *qc);
+static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
+static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t mv_interrupt(int irq, void *dev_instance,
                                struct pt_regs *regs);
 static void mv_eng_timeout(struct ata_port *ap);
@@ -362,11 +378,11 @@ static struct scsi_host_template mv_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = MV_USE_Q_DEPTH,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = MV_MAX_SG_CT / 2,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
@@ -430,6 +446,33 @@ static const struct ata_port_operations mv6_ops = {
        .host_stop              = mv_host_stop,
 };
 
+static const struct ata_port_operations mv_iie_ops = {
+       .port_disable           = ata_port_disable,
+
+       .tf_load                = ata_tf_load,
+       .tf_read                = ata_tf_read,
+       .check_status           = ata_check_status,
+       .exec_command           = ata_exec_command,
+       .dev_select             = ata_std_dev_select,
+
+       .phy_reset              = mv_phy_reset,
+
+       .qc_prep                = mv_qc_prep_iie,
+       .qc_issue               = mv_qc_issue,
+
+       .eng_timeout            = mv_eng_timeout,
+
+       .irq_handler            = mv_interrupt,
+       .irq_clear              = mv_irq_clear,
+
+       .scr_read               = mv_scr_read,
+       .scr_write              = mv_scr_write,
+
+       .port_start             = mv_port_start,
+       .port_stop              = mv_port_stop,
+       .host_stop              = mv_host_stop,
+};
+
 static const struct ata_port_info mv_port_info[] = {
        {  /* chip_504x */
                .sht            = &mv_sht,
@@ -467,6 +510,21 @@ static const struct ata_port_info mv_port_info[] = {
                .udma_mask      = 0x7f, /* udma0-6 */
                .port_ops       = &mv6_ops,
        },
+       {  /* chip_6042 */
+               .sht            = &mv_sht,
+               .host_flags     = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .udma_mask      = 0x7f, /* udma0-6 */
+               .port_ops       = &mv_iie_ops,
+       },
+       {  /* chip_7042 */
+               .sht            = &mv_sht,
+               .host_flags     = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                  MV_FLAG_DUAL_HC),
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .udma_mask      = 0x7f, /* udma0-6 */
+               .port_ops       = &mv_iie_ops,
+       },
 };
 
 static const struct pci_device_id mv_pci_tbl[] = {
@@ -477,6 +535,7 @@ static const struct pci_device_id mv_pci_tbl[] = {
 
        {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
        {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
+       {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
        {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
        {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
 
@@ -572,8 +631,8 @@ static void mv_irq_clear(struct ata_port *ap)
  *      @base: port base address
  *      @pp: port private data
  *
- *      Verify the local cache of the eDMA state is accurate with an
- *      assert.
+ *      Verify the local cache of the eDMA state is accurate with a
+ *      WARN_ON.
  *
  *      LOCKING:
  *      Inherited from caller.
@@ -584,15 +643,15 @@ static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
                writelfl(EDMA_EN, base + EDMA_CMD_OFS);
                pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
        }
-       assert(EDMA_EN & readl(base + EDMA_CMD_OFS));
+       WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
 }
 
 /**
  *      mv_stop_dma - Disable eDMA engine
  *      @ap: ATA channel to manipulate
  *
- *      Verify the local cache of the eDMA state is accurate with an
- *      assert.
+ *      Verify the local cache of the eDMA state is accurate with a
+ *      WARN_ON.
  *
  *      LOCKING:
  *      Inherited from caller.
@@ -610,7 +669,7 @@ static void mv_stop_dma(struct ata_port *ap)
                writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
                pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
        } else {
-               assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
+               WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
        }
 
        /* now properly wait for the eDMA to stop */
@@ -773,6 +832,33 @@ static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
        dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
 }
 
+static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
+{
+       u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
+
+       /* set up non-NCQ EDMA configuration */
+       cfg &= ~0x1f;           /* clear queue depth */
+       cfg &= ~EDMA_CFG_NCQ;   /* clear NCQ mode */
+       cfg &= ~(1 << 9);       /* disable equeue */
+
+       if (IS_GEN_I(hpriv))
+               cfg |= (1 << 8);        /* enab config burst size mask */
+
+       else if (IS_GEN_II(hpriv))
+               cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+
+       else if (IS_GEN_IIE(hpriv)) {
+               cfg |= (1 << 23);       /* dis RX PM port mask */
+               cfg &= ~(1 << 16);      /* dis FIS-based switching (for now) */
+               cfg &= ~(1 << 19);      /* dis 128-entry queue (for now?) */
+               cfg |= (1 << 18);       /* enab early completion */
+               cfg |= (1 << 17);       /* enab host q cache */
+               cfg |= (1 << 22);       /* enab cutthrough */
+       }
+
+       writelfl(cfg, port_mmio + EDMA_CFG_OFS);
+}
+
 /**
  *      mv_port_start - Port specific init/start routine.
  *      @ap: ATA channel to manipulate
@@ -786,6 +872,7 @@ static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
 static int mv_port_start(struct ata_port *ap)
 {
        struct device *dev = ap->host_set->dev;
+       struct mv_host_priv *hpriv = ap->host_set->private_data;
        struct mv_port_priv *pp;
        void __iomem *port_mmio = mv_ap_base(ap);
        void *mem;
@@ -829,17 +916,26 @@ static int mv_port_start(struct ata_port *ap)
        pp->sg_tbl = mem;
        pp->sg_tbl_dma = mem_dma;
 
-       writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT |
-                EDMA_CFG_WR_BUFF_LEN, port_mmio + EDMA_CFG_OFS);
+       mv_edma_cfg(hpriv, port_mmio);
 
        writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
        writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
                 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
 
-       writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
-       writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+       if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+               writelfl(pp->crqb_dma & 0xffffffff,
+                        port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+       else
+               writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
 
        writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
+
+       if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+               writelfl(pp->crpb_dma & 0xffffffff,
+                        port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+       else
+               writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+
        writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
                 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
 
@@ -960,21 +1056,19 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        struct ata_taskfile *tf;
        u16 flags = 0;
 
-       if (ATA_PROT_DMA != qc->tf.protocol) {
+       if (ATA_PROT_DMA != qc->tf.protocol)
                return;
-       }
 
        /* the req producer index should be the same as we remember it */
-       assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
-                EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-              pp->req_producer);
+       WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
+                 EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+               pp->req_producer);
 
        /* Fill in command request block
         */
-       if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
+       if (!(qc->tf.flags & ATA_TFLAG_WRITE))
                flags |= CRQB_FLAG_READ;
-       }
-       assert(MV_MAX_Q_DEPTH > qc->tag);
+       WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
        flags |= qc->tag << CRQB_TAG_SHIFT;
 
        pp->crqb[pp->req_producer].sg_addr =
@@ -1029,9 +1123,76 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
        mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);    /* last */
 
-       if (!(qc->flags & ATA_QCFLAG_DMAMAP)) {
+       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+               return;
+       mv_fill_sg(qc);
+}
+
+/**
+ *      mv_qc_prep_iie - Host specific command preparation.
+ *      @qc: queued command to prepare
+ *
+ *      This routine simply redirects to the general purpose routine
+ *      if command is not DMA.  Else, it handles prep of the CRQB
+ *      (command request block), does some sanity checking, and calls
+ *      the SG load routine.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct mv_port_priv *pp = ap->private_data;
+       struct mv_crqb_iie *crqb;
+       struct ata_taskfile *tf;
+       u32 flags = 0;
+
+       if (ATA_PROT_DMA != qc->tf.protocol)
+               return;
+
+       /* the req producer index should be the same as we remember it */
+       WARN_ON(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >>
+                 EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+               pp->req_producer);
+
+       /* Fill in Gen IIE command request block
+        */
+       if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+               flags |= CRQB_FLAG_READ;
+
+       WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+       flags |= qc->tag << CRQB_TAG_SHIFT;
+
+       crqb = (struct mv_crqb_iie *) &pp->crqb[pp->req_producer];
+       crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+       crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+       crqb->flags = cpu_to_le32(flags);
+
+       tf = &qc->tf;
+       crqb->ata_cmd[0] = cpu_to_le32(
+                       (tf->command << 16) |
+                       (tf->feature << 24)
+               );
+       crqb->ata_cmd[1] = cpu_to_le32(
+                       (tf->lbal << 0) |
+                       (tf->lbam << 8) |
+                       (tf->lbah << 16) |
+                       (tf->device << 24)
+               );
+       crqb->ata_cmd[2] = cpu_to_le32(
+                       (tf->hob_lbal << 0) |
+                       (tf->hob_lbam << 8) |
+                       (tf->hob_lbah << 16) |
+                       (tf->hob_feature << 24)
+               );
+       crqb->ata_cmd[3] = cpu_to_le32(
+                       (tf->nsect << 0) |
+                       (tf->hob_nsect << 8)
+               );
+
+       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
                return;
-       }
        mv_fill_sg(qc);
 }
 
@@ -1047,7 +1208,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
 {
        void __iomem *port_mmio = mv_ap_base(qc->ap);
        struct mv_port_priv *pp = qc->ap->private_data;
@@ -1065,12 +1226,12 @@ static int mv_qc_issue(struct ata_queued_cmd *qc)
        in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
 
        /* the req producer index should be the same as we remember it */
-       assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-              pp->req_producer);
+       WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+               pp->req_producer);
        /* until we do queuing, the queue should be empty at this point */
-       assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-              ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >>
-                EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+       WARN_ON(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+               ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >>
+                 EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
 
        mv_inc_q_index(&pp->req_producer);      /* now incr producer index */
 
@@ -1090,7 +1251,7 @@ static int mv_qc_issue(struct ata_queued_cmd *qc)
  *
  *      This routine is for use when the port is in DMA mode, when it
  *      will be using the CRPB (command response block) method of
- *      returning command completion information.  We assert indices
+ *      returning command completion information.  We check indices
  *      are good, grab status, and bump the response consumer index to
  *      prove that we're up to date.
  *
@@ -1106,16 +1267,16 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
        out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
 
        /* the response consumer index should be the same as we remember it */
-       assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-              pp->rsp_consumer);
+       WARN_ON(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+               pp->rsp_consumer);
 
        /* increment our consumer index... */
        pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer);
 
        /* and, until we do NCQ, there should only be 1 CRPB waiting */
-       assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >>
-                EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
-              pp->rsp_consumer);
+       WARN_ON(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >>
+                 EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) !=
+               pp->rsp_consumer);
 
        /* write out our inc'd consumer index so EDMA knows we're caught up */
        out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
@@ -1192,7 +1353,6 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
        u32 hc_irq_cause;
        int shift, port, port0, hard_port, handled;
        unsigned int err_mask;
-       u8 ata_status = 0;
 
        if (hc == 0) {
                port0 = 0;
@@ -1210,6 +1370,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
                hc,relevant,hc_irq_cause);
 
        for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+               u8 ata_status = 0;
                ap = host_set->ports[port];
                hard_port = port & MV_PORT_MASK;        /* range 0-3 */
                handled = 0;    /* ensure ata_status is set if handled++ */
@@ -1681,6 +1842,12 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
        m2 |= hpriv->signal[port].pre;
        m2 &= ~(1 << 16);
 
+       /* according to mvSata 3.6.1, some IIE values are fixed */
+       if (IS_GEN_IIE(hpriv)) {
+               m2 &= ~0xC30FF01F;
+               m2 |= 0x0000900F;
+       }
+
        writel(m2, port_mmio + PHY_MODE2);
 }
 
@@ -1846,7 +2013,6 @@ static void mv_phy_reset(struct ata_port *ap)
 static void mv_eng_timeout(struct ata_port *ap)
 {
        struct ata_queued_cmd *qc;
-       unsigned long flags;
 
        printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id);
        DPRINTK("All regs @ start of eng_timeout\n");
@@ -1861,22 +2027,8 @@ static void mv_eng_timeout(struct ata_port *ap)
        mv_err_intr(ap);
        mv_stop_and_reset(ap);
 
-       if (!qc) {
-               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-                      ap->id);
-       } else {
-               /* hack alert!  We cannot use the supplied completion
-                * function from inside the ->eh_strategy_handler() thread.
-                * libata is the only user of ->eh_strategy_handler() in
-                * any kernel, so the default scsi_done() assumes it is
-                * not being called from the SCSI EH.
-                */
-               spin_lock_irqsave(&ap->host_set->lock, flags);
-               qc->scsidone = scsi_finish_command;
-               qc->err_mask |= AC_ERR_OTHER;
-               ata_qc_complete(qc);
-               spin_unlock_irqrestore(&ap->host_set->lock, flags);
-       }
+       qc->err_mask |= AC_ERR_TIMEOUT;
+       ata_eh_qc_complete(qc);
 }
 
 /**
@@ -1995,6 +2147,27 @@ static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
                }
                break;
 
+       case chip_7042:
+       case chip_6042:
+               hpriv->ops = &mv6xxx_ops;
+
+               hp_flags |= MV_HP_GEN_IIE;
+
+               switch (rev_id) {
+               case 0x0:
+                       hp_flags |= MV_HP_ERRATA_XX42A0;
+                       break;
+               case 0x1:
+                       hp_flags |= MV_HP_ERRATA_60X1C0;
+                       break;
+               default:
+                       dev_printk(KERN_WARNING, &pdev->dev,
+                          "Applying 60X1C0 workarounds to unknown rev\n");
+                       hp_flags |= MV_HP_ERRATA_60X1C0;
+                       break;
+               }
+               break;
+
        default:
                printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
                return 1;
index bbbb55e..caffadc 100644 (file)
@@ -229,11 +229,11 @@ static struct scsi_host_template nv_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
index b0b0a69..84cb394 100644 (file)
@@ -46,7 +46,7 @@
 #include "sata_promise.h"
 
 #define DRV_NAME       "sata_promise"
-#define DRV_VERSION    "1.03"
+#define DRV_VERSION    "1.04"
 
 
 enum {
@@ -58,6 +58,7 @@ enum {
        PDC_GLOBAL_CTL          = 0x48, /* Global control/status (per port) */
        PDC_CTLSTAT             = 0x60, /* IDE control and status (per port) */
        PDC_SATA_PLUG_CSR       = 0x6C, /* SATA Plug control/status reg */
+       PDC2_SATA_PLUG_CSR      = 0x60, /* SATAII Plug control/status reg */
        PDC_SLEW_CTL            = 0x470, /* slew rate control reg */
 
        PDC_ERR_MASK            = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
@@ -67,8 +68,10 @@ enum {
        board_20319             = 1,    /* FastTrak S150 TX4 */
        board_20619             = 2,    /* FastTrak TX4000 */
        board_20771             = 3,    /* FastTrak TX2300 */
+       board_2057x             = 4,    /* SATAII150 Tx2plus */
+       board_40518             = 5,    /* SATAII150 Tx4 */
 
-       PDC_HAS_PATA            = (1 << 1), /* PDC20375 has PATA */
+       PDC_HAS_PATA            = (1 << 1), /* PDC20375/20575 has PATA */
 
        PDC_RESET               = (1 << 11), /* HDMA reset */
 
@@ -82,6 +85,10 @@ struct pdc_port_priv {
        dma_addr_t              pkt_dma;
 };
 
+struct pdc_host_priv {
+       int                     hotplug_offset;
+};
+
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -95,7 +102,8 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
 static void pdc_irq_clear(struct ata_port *ap);
-static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+static void pdc_host_stop(struct ata_host_set *host_set);
 
 
 static struct scsi_host_template pdc_ata_sht = {
@@ -103,11 +111,11 @@ static struct scsi_host_template pdc_ata_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
@@ -137,7 +145,7 @@ static const struct ata_port_operations pdc_sata_ops = {
        .scr_write              = pdc_sata_scr_write,
        .port_start             = pdc_port_start,
        .port_stop              = pdc_port_stop,
-       .host_stop              = ata_pci_host_stop,
+       .host_stop              = pdc_host_stop,
 };
 
 static const struct ata_port_operations pdc_pata_ops = {
@@ -158,7 +166,7 @@ static const struct ata_port_operations pdc_pata_ops = {
 
        .port_start             = pdc_port_start,
        .port_stop              = pdc_port_stop,
-       .host_stop              = ata_pci_host_stop,
+       .host_stop              = pdc_host_stop,
 };
 
 static const struct ata_port_info pdc_port_info[] = {
@@ -201,6 +209,26 @@ static const struct ata_port_info pdc_port_info[] = {
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &pdc_sata_ops,
        },
+
+       /* board_2057x */
+       {
+               .sht            = &pdc_ata_sht,
+               .host_flags     = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .port_ops       = &pdc_sata_ops,
+       },
+
+       /* board_40518 */
+       {
+               .sht            = &pdc_ata_sht,
+               .host_flags     = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+               .pio_mask       = 0x1f, /* pio0-4 */
+               .mwdma_mask     = 0x07, /* mwdma0-2 */
+               .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
+               .port_ops       = &pdc_sata_ops,
+       },
 };
 
 static const struct pci_device_id pdc_ata_pci_tbl[] = {
@@ -217,9 +245,9 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
        { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_2037x },
        { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_2037x },
+         board_2057x },
        { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_2037x },
+         board_2057x },
        { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_2037x },
 
@@ -227,12 +255,14 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
          board_20319 },
        { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_20319 },
+       { PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_20319 },
        { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_20319 },
        { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_20319 },
        { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_20319 },
+         board_40518 },
 
        { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          board_20619 },
@@ -261,12 +291,11 @@ static int pdc_port_start(struct ata_port *ap)
        if (rc)
                return rc;
 
-       pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+       pp = kzalloc(sizeof(*pp), GFP_KERNEL);
        if (!pp) {
                rc = -ENOMEM;
                goto err_out;
        }
-       memset(pp, 0, sizeof(*pp));
 
        pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
        if (!pp->pkt) {
@@ -298,6 +327,16 @@ static void pdc_port_stop(struct ata_port *ap)
 }
 
 
+static void pdc_host_stop(struct ata_host_set *host_set)
+{
+       struct pdc_host_priv *hp = host_set->private_data;
+
+       ata_pci_host_stop(host_set);
+
+       kfree(hp);
+}
+
+
 static void pdc_reset_port(struct ata_port *ap)
 {
        void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
@@ -394,19 +433,6 @@ static void pdc_eng_timeout(struct ata_port *ap)
        spin_lock_irqsave(&host_set->lock, flags);
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       if (!qc) {
-               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-                      ap->id);
-               goto out;
-       }
-
-       /* hack alert!  We cannot use the supplied completion
-        * function from inside the ->eh_strategy_handler() thread.
-        * libata is the only user of ->eh_strategy_handler() in
-        * any kernel, so the default scsi_done() assumes it is
-        * not being called from the SCSI EH.
-        */
-       qc->scsidone = scsi_finish_command;
 
        switch (qc->tf.protocol) {
        case ATA_PROT_DMA:
@@ -414,7 +440,6 @@ static void pdc_eng_timeout(struct ata_port *ap)
                printk(KERN_ERR "ata%u: command timeout\n", ap->id);
                drv_stat = ata_wait_idle(ap);
                qc->err_mask |= __ac_err_mask(drv_stat);
-               ata_qc_complete(qc);
                break;
 
        default:
@@ -424,12 +449,11 @@ static void pdc_eng_timeout(struct ata_port *ap)
                       ap->id, qc->tf.command, drv_stat);
 
                qc->err_mask |= ac_err_mask(drv_stat);
-               ata_qc_complete(qc);
                break;
        }
 
-out:
        spin_unlock_irqrestore(&host_set->lock, flags);
+       ata_eh_qc_complete(qc);
        DPRINTK("EXIT\n");
 }
 
@@ -495,14 +519,15 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
                VPRINTK("QUICK EXIT 2\n");
                return IRQ_NONE;
        }
+
+       spin_lock(&host_set->lock);
+
        mask &= 0xffff;         /* only 16 tags possible */
        if (!mask) {
                VPRINTK("QUICK EXIT 3\n");
-               return IRQ_NONE;
+               goto done_irq;
        }
 
-       spin_lock(&host_set->lock);
-
        writel(mask, mmio_base + PDC_INT_SEQMASK);
 
        for (i = 0; i < host_set->n_ports; i++) {
@@ -519,10 +544,10 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
                }
        }
 
-        spin_unlock(&host_set->lock);
-
        VPRINTK("EXIT\n");
 
+done_irq:
+       spin_unlock(&host_set->lock);
        return IRQ_RETVAL(handled);
 }
 
@@ -544,7 +569,7 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc)
        readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
 }
 
-static int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
+static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
 {
        switch (qc->tf.protocol) {
        case ATA_PROT_DMA:
@@ -600,6 +625,8 @@ static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
 static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
 {
        void __iomem *mmio = pe->mmio_base;
+       struct pdc_host_priv *hp = pe->private_data;
+       int hotplug_offset = hp->hotplug_offset;
        u32 tmp;
 
        /*
@@ -614,12 +641,12 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
        writel(tmp, mmio + PDC_FLASH_CTL);
 
        /* clear plug/unplug flags for all ports */
-       tmp = readl(mmio + PDC_SATA_PLUG_CSR);
-       writel(tmp | 0xff, mmio + PDC_SATA_PLUG_CSR);
+       tmp = readl(mmio + hotplug_offset);
+       writel(tmp | 0xff, mmio + hotplug_offset);
 
        /* mask plug/unplug ints */
-       tmp = readl(mmio + PDC_SATA_PLUG_CSR);
-       writel(tmp | 0xff0000, mmio + PDC_SATA_PLUG_CSR);
+       tmp = readl(mmio + hotplug_offset);
+       writel(tmp | 0xff0000, mmio + hotplug_offset);
 
        /* reduce TBG clock to 133 Mhz. */
        tmp = readl(mmio + PDC_TBG_MODE);
@@ -641,6 +668,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 {
        static int printed_version;
        struct ata_probe_ent *probe_ent = NULL;
+       struct pdc_host_priv *hp;
        unsigned long base;
        void __iomem *mmio_base;
        unsigned int board_idx = (unsigned int) ent->driver_data;
@@ -671,13 +699,12 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        if (rc)
                goto err_out_regions;
 
-       probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+       probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
        if (probe_ent == NULL) {
                rc = -ENOMEM;
                goto err_out_regions;
        }
 
-       memset(probe_ent, 0, sizeof(*probe_ent));
        probe_ent->dev = pci_dev_to_dev(pdev);
        INIT_LIST_HEAD(&probe_ent->node);
 
@@ -688,6 +715,16 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        }
        base = (unsigned long) mmio_base;
 
+       hp = kzalloc(sizeof(*hp), GFP_KERNEL);
+       if (hp == NULL) {
+               rc = -ENOMEM;
+               goto err_out_free_ent;
+       }
+
+       /* Set default hotplug offset */
+       hp->hotplug_offset = PDC_SATA_PLUG_CSR;
+       probe_ent->private_data = hp;
+
        probe_ent->sht          = pdc_port_info[board_idx].sht;
        probe_ent->host_flags   = pdc_port_info[board_idx].host_flags;
        probe_ent->pio_mask     = pdc_port_info[board_idx].pio_mask;
@@ -707,6 +744,10 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 
        /* notice 4-port boards */
        switch (board_idx) {
+       case board_40518:
+               /* Override hotplug offset for SATAII150 */
+               hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+               /* Fall through */
        case board_20319:
                        probe_ent->n_ports = 4;
 
@@ -716,6 +757,10 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
                probe_ent->port[2].scr_addr = base + 0x600;
                probe_ent->port[3].scr_addr = base + 0x700;
                break;
+       case board_2057x:
+               /* Override hotplug offset for SATAII150 */
+               hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+               /* Fall through */
        case board_2037x:
                probe_ent->n_ports = 2;
                break;
@@ -741,8 +786,10 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        /* initialize adapter */
        pdc_host_init(board_idx, probe_ent);
 
-       /* FIXME: check ata_device_add return value */
-       ata_device_add(probe_ent);
+       /* FIXME: Need any other frees than hp? */
+       if (!ata_device_add(probe_ent))
+               kfree(hp);
+
        kfree(probe_ent);
 
        return 0;
index 80480f0..9602f43 100644 (file)
@@ -120,7 +120,7 @@ static void qs_host_stop(struct ata_host_set *host_set);
 static void qs_port_stop(struct ata_port *ap);
 static void qs_phy_reset(struct ata_port *ap);
 static void qs_qc_prep(struct ata_queued_cmd *qc);
-static int qs_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
 static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
 static void qs_bmdma_stop(struct ata_queued_cmd *qc);
 static u8 qs_bmdma_status(struct ata_port *ap);
@@ -132,11 +132,11 @@ static struct scsi_host_template qs_ata_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = QS_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        //FIXME .use_clustering         = ATA_SHT_USE_CLUSTERING,
@@ -276,8 +276,8 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
        unsigned int nelem;
        u8 *prd = pp->pkt + QS_CPB_BYTES;
 
-       assert(qc->__sg != NULL);
-       assert(qc->n_elem > 0 || qc->pad_len > 0);
+       WARN_ON(qc->__sg == NULL);
+       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
 
        nelem = 0;
        ata_for_each_sg(sg, qc) {
@@ -352,7 +352,7 @@ static inline void qs_packet_start(struct ata_queued_cmd *qc)
        readl(chan + QS_CCT_CFF);          /* flush */
 }
 
-static int qs_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
 {
        struct qs_port_priv *pp = qc->ap->private_data;
 
index 9face3c..4f2a67e 100644 (file)
 #define DRV_VERSION    "0.9"
 
 enum {
+       /*
+        * host flags
+        */
        SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
        SIL_FLAG_MOD15WRITE     = (1 << 30),
+       SIL_DFL_HOST_FLAGS      = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_MMIO,
 
+       /*
+        * Controller IDs
+        */
        sil_3112                = 0,
-       sil_3112_m15w           = 1,
-       sil_3512                = 2,
-       sil_3114                = 3,
-
-       SIL_FIFO_R0             = 0x40,
-       SIL_FIFO_W0             = 0x41,
-       SIL_FIFO_R1             = 0x44,
-       SIL_FIFO_W1             = 0x45,
-       SIL_FIFO_R2             = 0x240,
-       SIL_FIFO_W2             = 0x241,
-       SIL_FIFO_R3             = 0x244,
-       SIL_FIFO_W3             = 0x245,
+       sil_3512                = 1,
+       sil_3114                = 2,
 
+       /*
+        * Register offsets
+        */
        SIL_SYSCFG              = 0x48,
+
+       /*
+        * Register bits
+        */
+       /* SYSCFG */
        SIL_MASK_IDE0_INT       = (1 << 22),
        SIL_MASK_IDE1_INT       = (1 << 23),
        SIL_MASK_IDE2_INT       = (1 << 24),
@@ -75,9 +81,12 @@ enum {
        SIL_MASK_4PORT          = SIL_MASK_2PORT |
                                  SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
 
-       SIL_IDE2_BMDMA          = 0x200,
-
+       /* BMDMA/BMDMA2 */
        SIL_INTR_STEERING       = (1 << 1),
+
+       /*
+        * Others
+        */
        SIL_QUIRK_MOD15WRITE    = (1 << 0),
        SIL_QUIRK_UDMA5MAX      = (1 << 1),
 };
@@ -90,13 +99,13 @@ static void sil_post_set_mode (struct ata_port *ap);
 
 
 static const struct pci_device_id sil_pci_tbl[] = {
-       { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
-       { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+       { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
        { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
        { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
-       { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
-       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
-       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w },
+       { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
        { }     /* terminate list */
 };
 
@@ -137,11 +146,11 @@ static struct scsi_host_template sil_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
@@ -159,7 +168,7 @@ static const struct ata_port_operations sil_ops = {
        .check_status           = ata_check_status,
        .exec_command           = ata_exec_command,
        .dev_select             = ata_std_dev_select,
-       .phy_reset              = sata_phy_reset,
+       .probe_reset            = ata_std_probe_reset,
        .post_set_mode          = sil_post_set_mode,
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -181,19 +190,7 @@ static const struct ata_port_info sil_port_info[] = {
        /* sil_3112 */
        {
                .sht            = &sil_sht,
-               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SRST | ATA_FLAG_MMIO,
-               .pio_mask       = 0x1f,                 /* pio0-4 */
-               .mwdma_mask     = 0x07,                 /* mwdma0-2 */
-               .udma_mask      = 0x3f,                 /* udma0-5 */
-               .port_ops       = &sil_ops,
-       },
-       /* sil_3112_15w - keep it sync'd w/ sil_3112 */
-       {
-               .sht            = &sil_sht,
-               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SRST | ATA_FLAG_MMIO |
-                                 SIL_FLAG_MOD15WRITE,
+               .host_flags     = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
@@ -202,9 +199,7 @@ static const struct ata_port_info sil_port_info[] = {
        /* sil_3512 */
        {
                .sht            = &sil_sht,
-               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SRST | ATA_FLAG_MMIO |
-                                 SIL_FLAG_RERR_ON_DMA_ACT,
+               .host_flags     = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
@@ -213,9 +208,7 @@ static const struct ata_port_info sil_port_info[] = {
        /* sil_3114 */
        {
                .sht            = &sil_sht,
-               .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SRST | ATA_FLAG_MMIO |
-                                 SIL_FLAG_RERR_ON_DMA_ACT,
+               .host_flags     = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
@@ -229,16 +222,17 @@ static const struct {
        unsigned long tf;       /* ATA taskfile register block */
        unsigned long ctl;      /* ATA control/altstatus register block */
        unsigned long bmdma;    /* DMA register block */
+       unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */
        unsigned long scr;      /* SATA control register block */
        unsigned long sien;     /* SATA Interrupt Enable register */
        unsigned long xfer_mode;/* data transfer mode register */
        unsigned long sfis_cfg; /* SATA FIS reception config register */
 } sil_port[] = {
        /* port 0 ... */
-       { 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4, 0x14c },
-       { 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4, 0x1cc },
-       { 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4, 0x34c },
-       { 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4, 0x3cc },
+       { 0x80, 0x8A, 0x00, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+       { 0xC0, 0xCA, 0x08, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+       { 0x280, 0x28A, 0x200, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+       { 0x2C0, 0x2CA, 0x208, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
        /* ... port 3 */
 };
 
@@ -354,22 +348,12 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
 {
        unsigned int n, quirks = 0;
-       unsigned char model_num[40];
-       const char *s;
-       unsigned int len;
+       unsigned char model_num[41];
 
-       ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
-                         sizeof(model_num));
-       s = &model_num[0];
-       len = strnlen(s, sizeof(model_num));
-
-       /* ATAPI specifies that empty space is blank-filled; remove blanks */
-       while ((len > 0) && (s[len - 1] == ' '))
-               len--;
+       ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
 
        for (n = 0; sil_blacklist[n].product; n++)
-               if (!memcmp(sil_blacklist[n].product, s,
-                           strlen(sil_blacklist[n].product))) {
+               if (!strcmp(sil_blacklist[n].product, model_num)) {
                        quirks = sil_blacklist[n].quirk;
                        break;
                }
@@ -380,16 +364,14 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
             (quirks & SIL_QUIRK_MOD15WRITE))) {
                printk(KERN_INFO "ata%u(%u): applying Seagate errata fix (mod15write workaround)\n",
                       ap->id, dev->devno);
-               ap->host->max_sectors = 15;
-               ap->host->hostt->max_sectors = 15;
-               dev->flags |= ATA_DFLAG_LOCK_SECTORS;
+               dev->max_sectors = 15;
                return;
        }
 
        /* limit to udma5 */
        if (quirks & SIL_QUIRK_UDMA5MAX) {
                printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n",
-                      ap->id, dev->devno, s);
+                      ap->id, dev->devno, model_num);
                ap->udma_mask &= ATA_UDMA5;
                return;
        }
@@ -431,13 +413,12 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                goto err_out_regions;
 
-       probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+       probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
        if (probe_ent == NULL) {
                rc = -ENOMEM;
                goto err_out_regions;
        }
 
-       memset(probe_ent, 0, sizeof(*probe_ent));
        INIT_LIST_HEAD(&probe_ent->node);
        probe_ent->dev = pci_dev_to_dev(pdev);
        probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
@@ -474,19 +455,12 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (cls) {
                cls >>= 3;
                cls++;  /* cls = (line_size/8)+1 */
-               writeb(cls, mmio_base + SIL_FIFO_R0);
-               writeb(cls, mmio_base + SIL_FIFO_W0);
-               writeb(cls, mmio_base + SIL_FIFO_R1);
-               writeb(cls, mmio_base + SIL_FIFO_W1);
-               if (ent->driver_data == sil_3114) {
-                       writeb(cls, mmio_base + SIL_FIFO_R2);
-                       writeb(cls, mmio_base + SIL_FIFO_W2);
-                       writeb(cls, mmio_base + SIL_FIFO_R3);
-                       writeb(cls, mmio_base + SIL_FIFO_W3);
-               }
+               for (i = 0; i < probe_ent->n_ports; i++)
+                       writew(cls << 8 | cls,
+                              mmio_base + sil_port[i].fifo_cfg);
        } else
                dev_printk(KERN_WARNING, &pdev->dev,
-                        "cache line size not set.  Driver may not function\n");
+                          "cache line size not set.  Driver may not function\n");
 
        /* Apply R_ERR on DMA activate FIS errata workaround */
        if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
@@ -509,10 +483,10 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                irq_mask = SIL_MASK_4PORT;
 
                /* flip the magic "make 4 ports work" bit */
-               tmp = readl(mmio_base + SIL_IDE2_BMDMA);
+               tmp = readl(mmio_base + sil_port[2].bmdma);
                if ((tmp & SIL_INTR_STEERING) == 0)
                        writel(tmp | SIL_INTR_STEERING,
-                              mmio_base + SIL_IDE2_BMDMA);
+                              mmio_base + sil_port[2].bmdma);
 
        } else {
                irq_mask = SIL_MASK_2PORT;
index 9231301..9a53a5e 100644 (file)
@@ -249,9 +249,9 @@ static u8 sil24_check_status(struct ata_port *ap);
 static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
 static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-static void sil24_phy_reset(struct ata_port *ap);
+static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
-static int sil24_qc_issue(struct ata_queued_cmd *qc);
+static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
 static void sil24_irq_clear(struct ata_port *ap);
 static void sil24_eng_timeout(struct ata_port *ap);
 static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -262,6 +262,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 static const struct pci_device_id sil24_pci_tbl[] = {
        { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
+       { 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
        { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
        { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
        { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
@@ -280,11 +281,11 @@ static struct scsi_host_template sil24_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
@@ -305,7 +306,7 @@ static const struct ata_port_operations sil24_ops = {
 
        .tf_read                = sil24_tf_read,
 
-       .phy_reset              = sil24_phy_reset,
+       .probe_reset            = sil24_probe_reset,
 
        .qc_prep                = sil24_qc_prep,
        .qc_issue               = sil24_qc_issue,
@@ -335,8 +336,8 @@ static struct ata_port_info sil24_port_info[] = {
        {
                .sht            = &sil24_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SRST | ATA_FLAG_MMIO |
-                                 ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4),
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+                                 SIL24_NPORTS2FLAG(4),
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
@@ -346,8 +347,8 @@ static struct ata_port_info sil24_port_info[] = {
        {
                .sht            = &sil24_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SRST | ATA_FLAG_MMIO |
-                                 ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2),
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+                                 SIL24_NPORTS2FLAG(2),
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
@@ -357,8 +358,8 @@ static struct ata_port_info sil24_port_info[] = {
        {
                .sht            = &sil24_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-                                 ATA_FLAG_SRST | ATA_FLAG_MMIO |
-                                 ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1),
+                                 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+                                 SIL24_NPORTS2FLAG(1),
                .pio_mask       = 0x1f,                 /* pio0-4 */
                .mwdma_mask     = 0x07,                 /* mwdma0-2 */
                .udma_mask      = 0x3f,                 /* udma0-5 */
@@ -370,7 +371,7 @@ static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
 {
        void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
 
-       if (ap->cdb_len == 16)
+       if (dev->cdb_len == 16)
                writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
        else
                writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
@@ -427,14 +428,23 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
        *tf = pp->tf;
 }
 
-static int sil24_issue_SRST(struct ata_port *ap)
+static int sil24_softreset(struct ata_port *ap, int verbose,
+                          unsigned int *class)
 {
        void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
        struct sil24_port_priv *pp = ap->private_data;
        struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
        dma_addr_t paddr = pp->cmd_block_dma;
+       unsigned long timeout = jiffies + ATA_TMOUT_BOOT * HZ;
        u32 irq_enable, irq_stat;
-       int cnt;
+
+       DPRINTK("ENTER\n");
+
+       if (!sata_dev_present(ap)) {
+               DPRINTK("PHY reports no device\n");
+               *class = ATA_DEV_NONE;
+               goto out;
+       }
 
        /* temporarily turn off IRQs during SRST */
        irq_enable = readl(port + PORT_IRQ_ENABLE_SET);
@@ -451,7 +461,7 @@ static int sil24_issue_SRST(struct ata_port *ap)
 
        writel((u32)paddr, port + PORT_CMD_ACTIVATE);
 
-       for (cnt = 0; cnt < 100; cnt++) {
+       do {
                irq_stat = readl(port + PORT_IRQ_STAT);
                writel(irq_stat, port + PORT_IRQ_STAT);         /* clear irq */
 
@@ -459,36 +469,42 @@ static int sil24_issue_SRST(struct ata_port *ap)
                if (irq_stat & (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR))
                        break;
 
-               msleep(1);
-       }
+               msleep(100);
+       } while (time_before(jiffies, timeout));
 
        /* restore IRQs */
        writel(irq_enable, port + PORT_IRQ_ENABLE_SET);
 
-       if (!(irq_stat & PORT_IRQ_COMPLETE))
-               return -1;
+       if (!(irq_stat & PORT_IRQ_COMPLETE)) {
+               DPRINTK("EXIT, srst failed\n");
+               return -EIO;
+       }
 
-       /* update TF */
        sil24_update_tf(ap);
+       *class = ata_dev_classify(&pp->tf);
+
+       if (*class == ATA_DEV_UNKNOWN)
+               *class = ATA_DEV_NONE;
+
+ out:
+       DPRINTK("EXIT, class=%u\n", *class);
        return 0;
 }
 
-static void sil24_phy_reset(struct ata_port *ap)
+static int sil24_hardreset(struct ata_port *ap, int verbose,
+                          unsigned int *class)
 {
-       struct sil24_port_priv *pp = ap->private_data;
+       unsigned int dummy_class;
 
-       __sata_phy_reset(ap);
-       if (ap->flags & ATA_FLAG_PORT_DISABLED)
-               return;
-
-       if (sil24_issue_SRST(ap) < 0) {
-               printk(KERN_ERR DRV_NAME
-                      " ata%u: SRST failed, disabling port\n", ap->id);
-               ap->ops->port_disable(ap);
-               return;
-       }
+       /* sil24 doesn't report device signature after hard reset */
+       return sata_std_hardreset(ap, verbose, &dummy_class);
+}
 
-       ap->device->class = ata_dev_classify(&pp->tf);
+static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes)
+{
+       return ata_drive_probe_reset(ap, ata_std_probeinit,
+                                    sil24_softreset, sil24_hardreset,
+                                    ata_std_postreset, classes);
 }
 
 static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
@@ -533,7 +549,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
                prb = &cb->atapi.prb;
                sge = cb->atapi.sge;
                memset(cb->atapi.cdb, 0, 32);
-               memcpy(cb->atapi.cdb, qc->cdb, ap->cdb_len);
+               memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
 
                if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
                        if (qc->tf.flags & ATA_TFLAG_WRITE)
@@ -557,7 +573,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
                sil24_fill_sg(qc, sge);
 }
 
-static int sil24_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
@@ -638,23 +654,10 @@ static void sil24_eng_timeout(struct ata_port *ap)
        struct ata_queued_cmd *qc;
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       if (!qc) {
-               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-                      ap->id);
-               return;
-       }
 
-       /*
-        * hack alert!  We cannot use the supplied completion
-        * function from inside the ->eh_strategy_handler() thread.
-        * libata is the only user of ->eh_strategy_handler() in
-        * any kernel, so the default scsi_done() assumes it is
-        * not being called from the SCSI EH.
-        */
        printk(KERN_ERR "ata%u: command timeout\n", ap->id);
-       qc->scsidone = scsi_finish_command;
-       qc->err_mask |= AC_ERR_OTHER;
-       ata_qc_complete(qc);
+       qc->err_mask |= AC_ERR_TIMEOUT;
+       ata_eh_qc_complete(qc);
 
        sil24_reset_controller(ap);
 }
@@ -895,6 +898,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        probe_ent->sht          = pinfo->sht;
        probe_ent->host_flags   = pinfo->host_flags;
        probe_ent->pio_mask     = pinfo->pio_mask;
+       probe_ent->mwdma_mask   = pinfo->mwdma_mask;
        probe_ent->udma_mask    = pinfo->udma_mask;
        probe_ent->port_ops     = pinfo->port_ops;
        probe_ent->n_ports      = SIL24_FLAG2NPORTS(pinfo->host_flags);
index 2df8c56..7fd45f8 100644 (file)
@@ -87,11 +87,11 @@ static struct scsi_host_template sis_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = ATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
index d847256..4aaccd5 100644 (file)
@@ -288,11 +288,11 @@ static struct scsi_host_template k2_sata_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
index bc87c16..9f8a768 100644 (file)
@@ -174,7 +174,7 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
 static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
                                 void *psource, u32 offset, u32 size);
 static void pdc20621_irq_clear(struct ata_port *ap);
-static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
+static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
 
 
 static struct scsi_host_template pdc_sata_sht = {
@@ -182,11 +182,11 @@ static struct scsi_host_template pdc_sata_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
@@ -460,7 +460,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
        unsigned int i, idx, total_len = 0, sgt_len;
        u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
 
-       assert(qc->flags & ATA_QCFLAG_DMAMAP);
+       WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
 
        VPRINTK("ata%u: ENTER\n", ap->id);
 
@@ -678,7 +678,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
        }
 }
 
-static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
+static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
 {
        switch (qc->tf.protocol) {
        case ATA_PROT_DMA:
@@ -866,26 +866,12 @@ static void pdc_eng_timeout(struct ata_port *ap)
        spin_lock_irqsave(&host_set->lock, flags);
 
        qc = ata_qc_from_tag(ap, ap->active_tag);
-       if (!qc) {
-               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-                      ap->id);
-               goto out;
-       }
-
-       /* hack alert!  We cannot use the supplied completion
-        * function from inside the ->eh_strategy_handler() thread.
-        * libata is the only user of ->eh_strategy_handler() in
-        * any kernel, so the default scsi_done() assumes it is
-        * not being called from the SCSI EH.
-        */
-       qc->scsidone = scsi_finish_command;
 
        switch (qc->tf.protocol) {
        case ATA_PROT_DMA:
        case ATA_PROT_NODATA:
                printk(KERN_ERR "ata%u: command timeout\n", ap->id);
                qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
-               ata_qc_complete(qc);
                break;
 
        default:
@@ -895,12 +881,11 @@ static void pdc_eng_timeout(struct ata_port *ap)
                       ap->id, qc->tf.command, drv_stat);
 
                qc->err_mask |= ac_err_mask(drv_stat);
-               ata_qc_complete(qc);
                break;
        }
 
-out:
        spin_unlock_irqrestore(&host_set->lock, flags);
+       ata_eh_qc_complete(qc);
        DPRINTK("EXIT\n");
 }
 
index 9635ca7..37a487b 100644 (file)
@@ -75,11 +75,11 @@ static struct scsi_host_template uli_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
index 6d5b0a7..ff65a0b 100644 (file)
@@ -94,11 +94,11 @@ static struct scsi_host_template svia_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
index e484e8d..b574379 100644 (file)
@@ -251,11 +251,11 @@ static struct scsi_host_template vsc_sata_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
+       .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
index ff82ccf..5d169a2 100644 (file)
@@ -584,8 +584,7 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
  *    keep a list of pending commands for final completion, and once we
  *    are ready to leave error handling we handle completion for real.
  **/
-static void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
-                              struct list_head *done_q)
+void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
 {
        scmd->device->host->host_failed--;
        scmd->eh_eflags = 0;
@@ -597,6 +596,7 @@ static void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
        scsi_setup_cmd_retry(scmd);
        list_move_tail(&scmd->eh_entry, done_q);
 }
+EXPORT_SYMBOL(scsi_eh_finish_cmd);
 
 /**
  * scsi_eh_get_sense - Get device sense data.
@@ -1425,7 +1425,7 @@ static void scsi_eh_ready_devs(struct Scsi_Host *shost,
  * @done_q:    list_head of processed commands.
  *
  **/
-static void scsi_eh_flush_done_q(struct list_head *done_q)
+void scsi_eh_flush_done_q(struct list_head *done_q)
 {
        struct scsi_cmnd *scmd, *next;
 
@@ -1454,6 +1454,7 @@ static void scsi_eh_flush_done_q(struct list_head *done_q)
                }
        }
 }
+EXPORT_SYMBOL(scsi_eh_flush_done_q);
 
 /**
  * scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
index 7410e09..00d7c0a 100644 (file)
@@ -1066,6 +1066,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
        port->mapbase   = res->start;
        port->membase   = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
        port->irq       = platform_get_irq(platdev, 0);
+       if (port->irq < 0)
+               port->irq = 0;
 
        ourport->clk    = clk_get(&platdev->dev, "uart");
 
index 85dacc9..b1222cd 100644 (file)
@@ -10,6 +10,7 @@ menu "USB support"
 config USB_ARCH_HAS_HCD
        boolean
        default y if USB_ARCH_HAS_OHCI
+       default y if USB_ARCH_HAS_EHCI
        default y if ARM                                # SL-811
        default PCI
 
@@ -22,6 +23,7 @@ config USB_ARCH_HAS_OHCI
        default y if ARCH_LH7A404
        default y if ARCH_S3C2410
        default y if PXA27x
+       default y if ARCH_AT91RM9200
        # PPC:
        default y if STB03xxx
        default y if PPC_MPC52xx
@@ -30,6 +32,13 @@ config USB_ARCH_HAS_OHCI
        # more:
        default PCI
 
+# some non-PCI hcds implement EHCI
+config USB_ARCH_HAS_EHCI
+       boolean
+       default y if PPC_83xx
+       default y if SOC_AU1200
+       default PCI
+
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
        tristate "Support for Host-side USB"
index 36e476d..bb36a1c 100644 (file)
@@ -15,10 +15,9 @@ obj-$(CONFIG_USB_OHCI_HCD)   += host/
 obj-$(CONFIG_USB_UHCI_HCD)     += host/
 obj-$(CONFIG_USB_SL811_HCD)    += host/
 obj-$(CONFIG_ETRAX_USB_HOST)   += host/
+obj-$(CONFIG_USB_OHCI_AT91)    += host/
 
 obj-$(CONFIG_USB_ACM)          += class/
-obj-$(CONFIG_USB_AUDIO)                += class/
-obj-$(CONFIG_USB_MIDI)         += class/
 obj-$(CONFIG_USB_PRINTER)      += class/
 
 obj-$(CONFIG_USB_STORAGE)      += storage/
@@ -48,6 +47,7 @@ obj-$(CONFIG_USB_SN9C102)     += media/
 obj-$(CONFIG_USB_STV680)       += media/
 obj-$(CONFIG_USB_VICAM)                += media/
 obj-$(CONFIG_USB_W9968CF)      += media/
+obj-$(CONFIG_USB_ZC0301)       += media/
 
 obj-$(CONFIG_USB_CATC)         += net/
 obj-$(CONFIG_USB_KAWETH)       += net/
index ef105a9..3a9102d 100644 (file)
@@ -4,53 +4,6 @@
 comment "USB Device Class drivers"
        depends on USB
 
-config OBSOLETE_OSS_USB_DRIVER
-       bool "Obsolete OSS USB drivers"
-       depends on USB && SOUND
-       help
-         This option enables support for the obsolete USB Audio and Midi
-         drivers that are scheduled for removal in the near future since
-         there are ALSA drivers for the same hardware.
-
-         Please contact Adrian Bunk <bunk@stusta.de> if you had to
-         say Y here because of missing support in the ALSA drivers.
-
-         If unsure, say N.
-
-config USB_AUDIO
-       tristate "USB Audio support"
-       depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
-       help
-         Say Y here if you want to connect USB audio equipment such as
-         speakers to your computer's USB port. You only need this if you use
-         the OSS sound driver; ALSA has its own option for usb audio support.
-
-         To compile this driver as a module, choose M here: the
-         module will be called audio.
-
-config USB_MIDI
-       tristate "USB MIDI support"
-       depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
-       ---help---
-         Say Y here if you want to connect a USB MIDI device to your
-         computer's USB port.  You only need this if you use the OSS
-         sound system; USB MIDI devices are supported by ALSA's USB
-         audio driver. This driver is for devices that comply with
-         'Universal Serial Bus Device Class Definition for MIDI Device'.
-
-         The following devices are known to work:
-         * Steinberg USB2MIDI
-         * Roland MPU64
-         * Roland PC-300
-         * Roland SC8850
-         * Roland UM-1
-         * Roland UM-2
-         * Roland UA-100
-         * Yamaha MU1000
-
-         To compile this driver as a module, choose M here: the
-         module will be called usb-midi.
-
 config USB_ACM
        tristate "USB Modem (CDC ACM) support"
        depends on USB
index 2294712..cc391e6 100644 (file)
@@ -4,6 +4,4 @@
 #
 
 obj-$(CONFIG_USB_ACM)          += cdc-acm.o
-obj-$(CONFIG_USB_AUDIO)                += audio.o
-obj-$(CONFIG_USB_MIDI)         += usb-midi.o
 obj-$(CONFIG_USB_PRINTER)      += usblp.o
diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
deleted file mode 100644 (file)
index 3ad9ee8..0000000
+++ /dev/null
@@ -1,3869 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     audio.c  --  USB Audio Class driver
- *
- *     Copyright (C) 1999, 2000, 2001, 2003, 2004
- *         Alan Cox (alan@lxorguk.ukuu.org.uk)
- *         Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- * Debugging:
- *     Use the 'lsusb' utility to dump the descriptors.
- *
- * 1999-09-07:  Alan Cox
- *             Parsing Audio descriptor patch
- * 1999-09-08:  Thomas Sailer
- *             Added OSS compatible data io functions; both parts of the
- *             driver remain to be glued together
- * 1999-09-10:  Thomas Sailer
- *             Beautified the driver. Added sample format conversions.
- *             Still not properly glued with the parsing code.
- *             The parsing code seems to have its problems btw,
- *             Since it parses all available configs but doesn't
- *             store which iface/altsetting belongs to which config.
- * 1999-09-20:  Thomas Sailer
- *             Threw out Alan's parsing code and implemented my own one.
- *             You cannot reasonnably linearly parse audio descriptors,
- *             especially the AudioClass descriptors have to be considered
- *             pointer lists. Mixer parsing untested, due to lack of device.
- *             First stab at synch pipe implementation, the Dallas USB DAC
- *             wants to use an Asynch out pipe. usb_audio_state now basically
- *             only contains lists of mixer and wave devices. We can therefore
- *             now have multiple mixer/wave devices per USB device.
- * 1999-10-28:  Thomas Sailer
- *             Converted to URB API. Fixed a taskstate/wakeup semantics mistake
- *             that made the driver consume all available CPU cycles.
- *             Now runs stable on UHCI-Acher/Fliegl/Sailer.
- * 1999-10-31:  Thomas Sailer
- *             Audio can now be unloaded if it is not in use by any mixer
- *             or dsp client (formerly you had to disconnect the audio devices
- *             from the USB port)
- *             Finally, about three months after ordering, my "Maxxtro SPK222"
- *             speakers arrived, isn't disdata a great mail order company 8-)
- *             Parse class specific endpoint descriptor of the audiostreaming
- *             interfaces and take the endpoint attributes from there.
- *             Unbelievably, the Philips USB DAC has a sampling rate range
- *             of over a decade, yet does not support the sampling rate control!
- *             No wonder it sounds so bad, has very audible sampling rate
- *             conversion distortion. Don't try to listen to it using
- *             decent headphones!
- *             "Let's make things better" -> but please Philips start with your
- *             own stuff!!!!
- * 1999-11-02:  Thomas Sailer
- *             It takes the Philips boxes several seconds to acquire synchronisation
- *             that means they won't play short sounds. Should probably maintain
- *             the ISO datastream even if there's nothing to play.
- *             Fix counting the total_bytes counter, RealPlayer G2 depends on it.
- * 1999-12-20:  Thomas Sailer
- *             Fix bad bug in conversion to per interface probing.
- *             disconnect was called multiple times for the audio device,
- *             leading to a premature freeing of the audio structures
- * 2000-05-13:  Thomas Sailer
- *             I don't remember who changed the find_format routine,
- *              but the change was completely broken for the Dallas
- *              chip. Anyway taking sampling rate into account in find_format
- *              is bad and should not be done unless there are devices with
- *              completely broken audio descriptors. Unless someone shows
- *              me such a descriptor, I will not allow find_format to
- *              take the sampling rate into account.
- *              Also, the former find_format made:
- *              - mpg123 play mono instead of stereo
- *              - sox completely fail for wav's with sample rates < 44.1kHz
- *                  for the Dallas chip.
- *              Also fix a rather long standing problem with applications that
- *              use "small" writes producing no sound at all.
- * 2000-05-15:  Thomas Sailer
- *             My fears came true, the Philips camera indeed has pretty stupid
- *              audio descriptors.
- * 2000-05-17:  Thomas Sailer
- *             Nemsoft spotted my stupid last minute change, thanks
- * 2000-05-19:  Thomas Sailer
- *             Fixed FEATURE_UNIT thinkos found thanks to the KC Technology
- *              Xtend device. Basically the driver treated FEATURE_UNIT's sourced
- *              by mono terminals as stereo.
- * 2000-05-20:  Thomas Sailer
- *             SELECTOR support (and thus selecting record channels from the mixer).
- *              Somewhat peculiar due to OSS interface limitations. Only works
- *              for channels where a "slider" is already in front of it (i.e.
- *              a MIXER unit or a FEATURE unit with volume capability).
- * 2000-11-26:  Thomas Sailer
- *              Workaround for Dallas DS4201. The DS4201 uses PCM8 as format tag for
- *              its 8 bit modes, but expects signed data (and should therefore have used PCM).
- * 2001-03-10:  Thomas Sailer
- *              provide abs function, prevent picking up a bogus kernel macro
- *              for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
- * 2001-06-16:  Bryce Nesbitt <bryce@obviously.com>
- *              Fix SNDCTL_DSP_STEREO API violation
- * 2003-04-08: Oliver Neukum (oliver@neukum.name):
- *             Setting a configuration is done by usbcore and must not be overridden
- * 2004-02-27:  Workaround for broken synch descriptors
- * 2004-03-07: Alan Stern <stern@rowland.harvard.edu>
- *             Add usb_ifnum_to_if() and usb_altnum_to_altsetting() support.
- *             Use the in-memory descriptors instead of reading them from the device.
- * 
- */
-
-/*
- * Strategy:
- *
- * Alan Cox and Thomas Sailer are starting to dig at opposite ends and
- * are hoping to meet in the middle, just like tunnel diggers :)
- * Alan tackles the descriptor parsing, Thomas the actual data IO and the
- * OSS compatible interface.
- *
- * Data IO implementation issues
- *
- * A mmap'able ring buffer per direction is implemented, because
- * almost every OSS app expects it. It is however impractical to
- * transmit/receive USB data directly into and out of the ring buffer,
- * due to alignment and synchronisation issues. Instead, the ring buffer
- * feeds a constant time delay line that handles the USB issues.
- *
- * Now we first try to find an alternate setting that exactly matches
- * the sample format requested by the user. If we find one, we do not
- * need to perform any sample rate conversions. If there is no matching
- * altsetting, we choose the closest one and perform sample format
- * conversions. We never do sample rate conversion; these are too
- * expensive to be performed in the kernel.
- *
- * Current status: no known HCD-specific issues.
- *
- * Generally: Due to the brokenness of the Audio Class spec
- * it seems generally impossible to write a generic Audio Class driver,
- * so a reasonable driver should implement the features that are actually
- * used.
- *
- * Parsing implementation issues
- *
- * One cannot reasonably parse the AudioClass descriptors linearly.
- * Therefore the current implementation features routines to look
- * for a specific descriptor in the descriptor list.
- *
- * How does the parsing work? First, all interfaces are searched
- * for an AudioControl class interface. If found, the config descriptor
- * that belongs to the current configuration is searched and
- * the HEADER descriptor is found. It contains a list of
- * all AudioStreaming and MIDIStreaming devices. This list is then walked,
- * and all AudioStreaming interfaces are classified into input and output
- * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming
- * is currently not supported). The input & output list is then used
- * to group inputs and outputs together and issued pairwise to the
- * AudioStreaming class parser. Finally, all OUTPUT_TERMINAL descriptors
- * are walked and issued to the mixer construction routine.
- *
- * The AudioStreaming parser simply enumerates all altsettings belonging
- * to the specified interface. It looks for AS_GENERAL and FORMAT_TYPE
- * class specific descriptors to extract the sample format/sample rate
- * data. Only sample format types PCM and PCM8 are supported right now, and
- * only FORMAT_TYPE_I is handled. The isochronous data endpoint needs to
- * be the first endpoint of the interface, and the optional synchronisation
- * isochronous endpoint the second one.
- *
- * Mixer construction works as follows: The various TERMINAL and UNIT
- * descriptors span a tree from the root (OUTPUT_TERMINAL) through the
- * intermediate nodes (UNITs) to the leaves (INPUT_TERMINAL). We walk
- * that tree in a depth first manner. FEATURE_UNITs may contribute volume,
- * bass and treble sliders to the mixer, MIXER_UNITs volume sliders.
- * The terminal type encoded in the INPUT_TERMINALs feeds a heuristic
- * to determine "meaningful" OSS slider numbers, however we will see
- * how well this works in practice. Other features are not used at the
- * moment, they seem less often used. Also, it seems difficult at least
- * to construct recording source switches from SELECTOR_UNITs, but
- * since there are not many USB ADC's available, we leave that for later.
- */
-
-/*****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/module.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <linux/usb.h>
-
-#include "audio.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.0.0"
-#define DRIVER_AUTHOR "Alan Cox <alan@lxorguk.ukuu.org.uk>, Thomas Sailer (sailer@ife.ee.ethz.ch)"
-#define DRIVER_DESC "USB Audio Class driver"
-
-#define AUDIO_DEBUG 1
-
-#define SND_DEV_DSP16   5
-
-#define dprintk(x)
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Linked list of all audio devices...
- */
-static struct list_head audiodevs = LIST_HEAD_INIT(audiodevs);
-static DECLARE_MUTEX(open_sem);
-
-/*
- * wait queue for processes wanting to open an USB audio device
- */
-static DECLARE_WAIT_QUEUE_HEAD(open_wait);
-
-
-#define MAXFORMATS        MAX_ALT
-#define DMABUFSHIFT       17  /* 128k worth of DMA buffer */
-#define NRSGBUF           (1U<<(DMABUFSHIFT-PAGE_SHIFT))
-
-/*
- * This influences:
- * - Latency
- * - Interrupt rate
- * - Synchronisation behaviour
- * Don't touch this if you don't understand all of the above.
- */
-#define DESCFRAMES  5
-#define SYNCFRAMES  DESCFRAMES
-
-#define MIXFLG_STEREOIN   1
-#define MIXFLG_STEREOOUT  2
-
-struct mixerchannel {
-       __u16 value;
-       __u16 osschannel;  /* number of the OSS channel */
-       __s16 minval, maxval;
-       __u16 slctunitid;
-       __u8 unitid;
-       __u8 selector;
-       __u8 chnum;
-       __u8 flags;
-};
-
-struct audioformat {
-       unsigned int format;
-       unsigned int sratelo;
-       unsigned int sratehi;
-       unsigned char altsetting;
-       unsigned char attributes;
-};
-
-struct dmabuf {
-       /* buffer data format */
-       unsigned int format;
-       unsigned int srate;
-       /* physical buffer */
-       unsigned char *sgbuf[NRSGBUF];
-       unsigned bufsize;
-       unsigned numfrag;
-       unsigned fragshift;
-       unsigned wrptr, rdptr;
-       unsigned total_bytes;
-       int count;
-       unsigned error; /* over/underrun */
-       wait_queue_head_t wait;
-       /* redundant, but makes calculations easier */
-       unsigned fragsize;
-       unsigned dmasize;
-       /* OSS stuff */
-       unsigned mapped:1;
-       unsigned ready:1;
-       unsigned ossfragshift;
-       int ossmaxfrags;
-       unsigned subdivision;
-};
-
-struct usb_audio_state;
-
-#define FLG_URB0RUNNING   1
-#define FLG_URB1RUNNING   2
-#define FLG_SYNC0RUNNING  4
-#define FLG_SYNC1RUNNING  8
-#define FLG_RUNNING      16
-#define FLG_CONNECTED    32
-
-struct my_data_urb {
-       struct urb *urb;
-};
-
-struct my_sync_urb {
-       struct urb *urb;
-};
-
-
-struct usb_audiodev {
-       struct list_head list;
-       struct usb_audio_state *state;
-       
-       /* soundcore stuff */
-       int dev_audio;
-
-       /* wave stuff */
-       mode_t open_mode;
-       spinlock_t lock;         /* DMA buffer access spinlock */
-
-       struct usbin {
-               int interface;           /* Interface number, -1 means not used */
-               unsigned int format;     /* USB data format */
-               unsigned int datapipe;   /* the data input pipe */
-               unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but adaptive IN mode */
-               unsigned int syncinterval;  /* P for adaptive IN mode, 0 otherwise */
-               unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-               unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
-               unsigned int phase;      /* phase accumulator */
-               unsigned int flags;      /* see FLG_ defines */
-               
-               struct my_data_urb durb[2];  /* ISO descriptors for the data endpoint */
-               struct my_sync_urb surb[2];  /* ISO sync pipe descriptor if needed */
-               
-               struct dmabuf dma;
-       } usbin;
-
-       struct usbout {
-               int interface;           /* Interface number, -1 means not used */
-               unsigned int format;     /* USB data format */
-               unsigned int datapipe;   /* the data input pipe */
-               unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but asynchronous OUT mode */
-               unsigned int syncinterval;  /* P for asynchronous OUT mode, 0 otherwise */
-               unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-               unsigned int freqm;      /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-               unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
-               unsigned int phase;      /* phase accumulator */
-               unsigned int flags;      /* see FLG_ defines */
-
-               struct my_data_urb durb[2];  /* ISO descriptors for the data endpoint */
-               struct my_sync_urb surb[2];  /* ISO sync pipe descriptor if needed */
-               
-               struct dmabuf dma;
-       } usbout;
-
-
-       unsigned int numfmtin, numfmtout;
-       struct audioformat fmtin[MAXFORMATS];
-       struct audioformat fmtout[MAXFORMATS];
-};  
-
-struct usb_mixerdev {
-       struct list_head list;
-       struct usb_audio_state *state;
-
-       /* soundcore stuff */
-       int dev_mixer;
-
-       unsigned char iface;  /* interface number of the AudioControl interface */
-
-       /* USB format descriptions */
-       unsigned int numch, modcnt;
-
-       /* mixch is last and gets allocated dynamically */
-       struct mixerchannel ch[0];
-};
-
-struct usb_audio_state {
-       struct list_head audiodev;
-
-       /* USB device */
-       struct usb_device *usbdev;
-
-       struct list_head audiolist;
-       struct list_head mixerlist;
-
-       unsigned count;  /* usage counter; NOTE: the usb stack is also considered a user */
-};
-
-/* private audio format extensions */
-#define AFMT_STEREO        0x80000000
-#define AFMT_ISSTEREO(x)   ((x) & AFMT_STEREO)
-#define AFMT_IS16BIT(x)    ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE))
-#define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE))
-#define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0))
-#define AFMT_BYTES(x)      (1<<AFMT_BYTESSHFIT(x))
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
-       unsigned r = 0;
-       
-       if (x >= 0x10000) {
-               x >>= 16;
-               r += 16;
-       }
-       if (x >= 0x100) {
-               x >>= 8;
-               r += 8;
-       }
-       if (x >= 0x10) {
-               x >>= 4;
-               r += 4;
-       }
-       if (x >= 4) {
-               x >>= 2;
-               r += 2;
-       }
-       if (x >= 2)
-               r++;
-       return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * OSS compatible ring buffer management. The ring buffer may be mmap'ed into
- * an application address space.
- *
- * I first used the rvmalloc stuff copied from bttv. Alan Cox did not like it, so
- * we now use an array of pointers to a single page each. This saves us the
- * kernel page table manipulations, but we have to do a page table alike mechanism
- * (though only one indirection) in software.
- */
-
-static void dmabuf_release(struct dmabuf *db)
-{
-       unsigned int nr;
-       void *p;
-
-       for(nr = 0; nr < NRSGBUF; nr++) {
-               if (!(p = db->sgbuf[nr]))
-                       continue;
-               ClearPageReserved(virt_to_page(p));
-               free_page((unsigned long)p);
-               db->sgbuf[nr] = NULL;
-       }
-       db->mapped = db->ready = 0;
-}
-
-static int dmabuf_init(struct dmabuf *db)
-{
-       unsigned int nr, bytepersec, bufs;
-       void *p;
-
-       /* initialize some fields */
-       db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
-       /* calculate required buffer size */
-       bytepersec = db->srate << AFMT_BYTESSHIFT(db->format);
-       bufs = 1U << DMABUFSHIFT;
-       if (db->ossfragshift) {
-               if ((1000 << db->ossfragshift) < bytepersec)
-                       db->fragshift = ld2(bytepersec/1000);
-               else
-                       db->fragshift = db->ossfragshift;
-       } else {
-               db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-               if (db->fragshift < 3)
-                       db->fragshift = 3;
-       }
-       db->numfrag = bufs >> db->fragshift;
-       while (db->numfrag < 4 && db->fragshift > 3) {
-               db->fragshift--;
-               db->numfrag = bufs >> db->fragshift;
-       }
-       db->fragsize = 1 << db->fragshift;
-       if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-               db->numfrag = db->ossmaxfrags;
-       db->dmasize = db->numfrag << db->fragshift;
-       for(nr = 0; nr < NRSGBUF; nr++) {
-               if (!db->sgbuf[nr]) {
-                       p = (void *)get_zeroed_page(GFP_KERNEL);
-                       if (!p)
-                               return -ENOMEM;
-                       db->sgbuf[nr] = p;
-                       SetPageReserved(virt_to_page(p));
-               }
-               memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE);
-               if ((nr << PAGE_SHIFT) >= db->dmasize)
-                       break;
-       }
-       db->bufsize = nr << PAGE_SHIFT;
-       db->ready = 1;
-       dprintk((KERN_DEBUG "usbaudio: dmabuf_init bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
-                "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x srate %d\n",
-                bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
-                db->numfrag, db->dmasize, db->bufsize, db->format, db->srate));
-       return 0;
-}
-
-static int dmabuf_mmap(struct vm_area_struct *vma, struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
-{
-       unsigned int nr;
-
-       if (!db->ready || db->mapped || (start | size) & (PAGE_SIZE-1) || size > db->bufsize)
-               return -EINVAL;
-       size >>= PAGE_SHIFT;
-       for(nr = 0; nr < size; nr++)
-               if (!db->sgbuf[nr])
-                       return -EINVAL;
-       db->mapped = 1;
-       for(nr = 0; nr < size; nr++) {
-               unsigned long pfn;
-
-               pfn = virt_to_phys(db->sgbuf[nr]) >> PAGE_SHIFT;
-               if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, prot))
-                       return -EAGAIN;
-               start += PAGE_SIZE;
-       }
-       return 0;
-}
-
-static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size)
-{
-       unsigned int pgrem, rem;
-
-       db->total_bytes += size;
-       for (;;) {
-               if (size <= 0)
-                       return;
-               pgrem = ((~db->wrptr) & (PAGE_SIZE-1)) + 1;
-               if (pgrem > size)
-                       pgrem = size;
-               rem = db->dmasize - db->wrptr;
-               if (pgrem > rem)
-                       pgrem = rem;
-               memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem);
-               size -= pgrem;
-               buffer += pgrem;
-               db->wrptr += pgrem;
-               if (db->wrptr >= db->dmasize)
-                       db->wrptr = 0;
-       }
-}
-
-static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size)
-{
-       unsigned int pgrem, rem;
-
-       db->total_bytes += size;
-       for (;;) {
-               if (size <= 0)
-                       return;
-               pgrem = ((~db->rdptr) & (PAGE_SIZE-1)) + 1;
-               if (pgrem > size)
-                       pgrem = size;
-               rem = db->dmasize - db->rdptr;
-               if (pgrem > rem)
-                       pgrem = rem;
-               memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem);
-               size -= pgrem;
-               buffer += pgrem;
-               db->rdptr += pgrem;
-               if (db->rdptr >= db->dmasize)
-                       db->rdptr = 0;
-       }
-}
-
-static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void __user *buffer, unsigned int size)
-{
-       unsigned int pgrem, rem;
-
-       if (!db->ready || db->mapped)
-               return -EINVAL;
-       for (;;) {
-               if (size <= 0)
-                       return 0;
-               pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
-               if (pgrem > size)
-                       pgrem = size;
-               rem = db->dmasize - ptr;
-               if (pgrem > rem)
-                       pgrem = rem;
-               if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem))
-                       return -EFAULT;
-               size -= pgrem;
-               buffer += pgrem;
-               ptr += pgrem;
-               if (ptr >= db->dmasize)
-                       ptr = 0;
-       }
-}
-
-static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void __user *buffer, unsigned int size)
-{
-       unsigned int pgrem, rem;
-
-       if (!db->ready || db->mapped)
-               return -EINVAL;
-       for (;;) {
-               if (size <= 0)
-                       return 0;
-               pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
-               if (pgrem > size)
-                       pgrem = size;
-               rem = db->dmasize - ptr;
-               if (pgrem > rem)
-                       pgrem = rem;
-               if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem))
-                       return -EFAULT;
-               size -= pgrem;
-               buffer += pgrem;
-               ptr += pgrem;
-               if (ptr >= db->dmasize)
-                       ptr = 0;
-       }
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * USB I/O code. We do sample format conversion if necessary
- */
-
-static void usbin_stop(struct usb_audiodev *as)
-{
-       struct usbin *u = &as->usbin;
-       unsigned long flags;
-       unsigned int i, notkilled = 1;
-
-       spin_lock_irqsave(&as->lock, flags);
-       u->flags &= ~FLG_RUNNING;
-       i = u->flags;
-       spin_unlock_irqrestore(&as->lock, flags);
-       while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-               if (notkilled)
-                       schedule_timeout_interruptible(1);
-               else
-                       schedule_timeout_uninterruptible(1);
-               spin_lock_irqsave(&as->lock, flags);
-               i = u->flags;
-               spin_unlock_irqrestore(&as->lock, flags);
-               if (notkilled && signal_pending(current)) {
-                       if (i & FLG_URB0RUNNING)
-                               usb_kill_urb(u->durb[0].urb);
-                       if (i & FLG_URB1RUNNING)
-                               usb_kill_urb(u->durb[1].urb);
-                       if (i & FLG_SYNC0RUNNING)
-                               usb_kill_urb(u->surb[0].urb);
-                       if (i & FLG_SYNC1RUNNING)
-                               usb_kill_urb(u->surb[1].urb);
-                       notkilled = 0;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       kfree(u->durb[0].urb->transfer_buffer);
-       kfree(u->durb[1].urb->transfer_buffer);
-       kfree(u->surb[0].urb->transfer_buffer);
-       kfree(u->surb[1].urb->transfer_buffer);
-       u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
-               u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
-}
-
-static inline void usbin_release(struct usb_audiodev *as)
-{
-       usbin_stop(as);
-}
-
-static void usbin_disc(struct usb_audiodev *as)
-{
-       struct usbin *u = &as->usbin;
-
-       unsigned long flags;
-
-       spin_lock_irqsave(&as->lock, flags);
-       u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);
-       spin_unlock_irqrestore(&as->lock, flags);
-       usbin_stop(as);
-}
-
-static void conversion(const void *ibuf, unsigned int ifmt, void *obuf, unsigned int ofmt, void *tmp, unsigned int scnt)
-{
-       unsigned int cnt, i;
-       __s16 *sp, *sp2, s;
-       unsigned char *bp;
-
-       cnt = scnt;
-       if (AFMT_ISSTEREO(ifmt))
-               cnt <<= 1;
-       sp = ((__s16 *)tmp) + cnt;
-       switch (ifmt & ~AFMT_STEREO) {
-       case AFMT_U8:
-               for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
-                       bp--;
-                       sp--;
-                       *sp = (*bp ^ 0x80) << 8;
-               }
-               break;
-                       
-       case AFMT_S8:
-               for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
-                       bp--;
-                       sp--;
-                       *sp = *bp << 8;
-               }
-               break;
-               
-       case AFMT_U16_LE:
-               for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-                       bp -= 2;
-                       sp--;
-                       *sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
-               }
-               break;
-
-       case AFMT_U16_BE:
-               for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-                       bp -= 2;
-                       sp--;
-                       *sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
-               }
-               break;
-
-       case AFMT_S16_LE:
-               for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-                       bp -= 2;
-                       sp--;
-                       *sp = bp[0] | (bp[1] << 8);
-               }
-               break;
-
-       case AFMT_S16_BE:
-               for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-                       bp -= 2;
-                       sp--;
-                       *sp = bp[1] | (bp[0] << 8);
-               }
-               break;
-       }
-       if (!AFMT_ISSTEREO(ifmt) && AFMT_ISSTEREO(ofmt)) {
-               /* expand from mono to stereo */
-               for (sp = ((__s16 *)tmp)+scnt, sp2 = ((__s16 *)tmp)+2*scnt, i = 0; i < scnt; i++) {
-                       sp--;
-                       sp2 -= 2;
-                       sp2[0] = sp2[1] = sp[0];
-               }
-       }
-       if (AFMT_ISSTEREO(ifmt) && !AFMT_ISSTEREO(ofmt)) {
-               /* contract from stereo to mono */
-               for (sp = sp2 = ((__s16 *)tmp), i = 0; i < scnt; i++, sp++, sp2 += 2)
-                       sp[0] = (sp2[0] + sp2[1]) >> 1;
-       }
-       cnt = scnt;
-       if (AFMT_ISSTEREO(ofmt))
-               cnt <<= 1;
-       sp = ((__s16 *)tmp);
-       bp = ((unsigned char *)obuf);
-       switch (ofmt & ~AFMT_STEREO) {
-       case AFMT_U8:
-               for (i = 0; i < cnt; i++, sp++, bp++)
-                       *bp = (*sp >> 8) ^ 0x80;
-               break;
-
-       case AFMT_S8:
-               for (i = 0; i < cnt; i++, sp++, bp++)
-                       *bp = *sp >> 8;
-               break;
-
-       case AFMT_U16_LE:
-               for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                       s = *sp;
-                       bp[0] = s;
-                       bp[1] = (s >> 8) ^ 0x80;
-               }
-               break;
-
-       case AFMT_U16_BE:
-               for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                       s = *sp;
-                       bp[1] = s;
-                       bp[0] = (s >> 8) ^ 0x80;
-               }
-               break;
-
-       case AFMT_S16_LE:
-               for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                       s = *sp;
-                       bp[0] = s;
-                       bp[1] = s >> 8;
-               }
-               break;
-
-       case AFMT_S16_BE:
-               for (i = 0; i < cnt; i++, sp++, bp += 2) {
-                       s = *sp;
-                       bp[1] = s;
-                       bp[0] = s >> 8;
-               }
-               break;
-       }
-       
-}
-
-static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
-{
-       union {
-               __s16 s[64];
-               unsigned char b[0];
-       } tmp;
-       unsigned int scnt, maxs, ufmtsh, dfmtsh;
-
-       ufmtsh = AFMT_BYTESSHIFT(u->format);
-       dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-       maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
-       while (samples > 0) {
-               scnt = samples;
-               if (scnt > maxs)
-                       scnt = maxs;
-               conversion(buffer, u->format, tmp.b, u->dma.format, tmp.b, scnt);
-               dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
-               buffer += scnt << ufmtsh;
-               samples -= scnt;
-       }
-}              
-
-static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
-{
-       unsigned int i, maxsize, offs;
-
-       maxsize = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-       //printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
-       for (i = offs = 0; i < DESCFRAMES; i++, offs += maxsize) {
-               urb->iso_frame_desc[i].length = maxsize;
-               urb->iso_frame_desc[i].offset = offs;
-       }
-       urb->interval = 1;
-       return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- * convert sample format on the fly if necessary
- */
-static int usbin_retire_desc(struct usbin *u, struct urb *urb)
-{
-       unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
-       unsigned char *cp;
-
-       ufmtsh = AFMT_BYTESSHIFT(u->format);
-       dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-       for (i = 0; i < DESCFRAMES; i++) {
-               cp = ((unsigned char *)urb->transfer_buffer) + urb->iso_frame_desc[i].offset;
-               if (urb->iso_frame_desc[i].status) {
-                       dprintk((KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-                       continue;
-               }
-               scnt = urb->iso_frame_desc[i].actual_length >> ufmtsh;
-               if (!scnt)
-                       continue;
-               cnt = scnt << dfmtsh;
-               if (!u->dma.mapped) {
-                       dmafree = u->dma.dmasize - u->dma.count;
-                       if (cnt > dmafree) {
-                               scnt = dmafree >> dfmtsh;
-                               cnt = scnt << dfmtsh;
-                               err++;
-                       }
-               }
-               u->dma.count += cnt;
-               if (u->format == u->dma.format) {
-                       /* we do not need format conversion */
-                       dprintk((KERN_DEBUG "usbaudio: no sample format conversion\n"));
-                       dmabuf_copyin(&u->dma, cp, cnt);
-               } else {
-                       /* we need sampling format conversion */
-                       dprintk((KERN_DEBUG "usbaudio: sample format conversion %x != %x\n", u->format, u->dma.format));
-                       usbin_convert(u, cp, scnt);
-               }
-       }
-       if (err)
-               u->dma.error++;
-       if (u->dma.count >= (signed)u->dma.fragsize)
-               wake_up(&u->dma.wait);
-       return err ? -1 : 0;
-}
-
-static void usbin_completed(struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-       struct usbin *u = &as->usbin;
-       unsigned long flags;
-       unsigned int mask;
-       int suret = 0;
-
-#if 0
-       printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-       if (urb == u->durb[0].urb)
-               mask = FLG_URB0RUNNING;
-       else if (urb == u->durb[1].urb)
-               mask = FLG_URB1RUNNING;
-       else {
-               mask = 0;
-               printk(KERN_ERR "usbin_completed: panic: unknown URB\n");
-       }
-       urb->dev = as->state->usbdev;
-       spin_lock_irqsave(&as->lock, flags);
-       if (!usbin_retire_desc(u, urb) &&
-           u->flags & FLG_RUNNING &&
-           !usbin_prepare_desc(u, urb) && 
-           (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-               u->flags |= mask;
-       } else {
-               u->flags &= ~(mask | FLG_RUNNING);
-               wake_up(&u->dma.wait);
-               printk(KERN_DEBUG "usbin_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret);
-       }
-       spin_unlock_irqrestore(&as->lock, flags);
-}
-
-/*
- * we output sync data
- */
-static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
-{
-       unsigned char *cp = urb->transfer_buffer;
-       unsigned int i, offs;
-       
-       for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3, cp += 3) {
-               urb->iso_frame_desc[i].length = 3;
-               urb->iso_frame_desc[i].offset = offs;
-               cp[0] = u->freqn;
-               cp[1] = u->freqn >> 8;
-               cp[2] = u->freqn >> 16;
-       }
-       urb->interval = 1;
-       return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb)
-{
-       unsigned int i;
-       
-       for (i = 0; i < SYNCFRAMES; i++)
-               if (urb->iso_frame_desc[0].status)
-                       dprintk((KERN_DEBUG "usbin_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-       return 0;
-}
-
-static void usbin_sync_completed(struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-       struct usbin *u = &as->usbin;
-       unsigned long flags;
-       unsigned int mask;
-       int suret = 0;
-
-#if 0
-       printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-       if (urb == u->surb[0].urb)
-               mask = FLG_SYNC0RUNNING;
-       else if (urb == u->surb[1].urb)
-               mask = FLG_SYNC1RUNNING;
-       else {
-               mask = 0;
-               printk(KERN_ERR "usbin_sync_completed: panic: unknown URB\n");
-       }
-       urb->dev = as->state->usbdev;
-       spin_lock_irqsave(&as->lock, flags);
-       if (!usbin_sync_retire_desc(u, urb) &&
-           u->flags & FLG_RUNNING &&
-           !usbin_sync_prepare_desc(u, urb) && 
-           (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-               u->flags |= mask;
-       } else {
-               u->flags &= ~(mask | FLG_RUNNING);
-               wake_up(&u->dma.wait);
-               dprintk((KERN_DEBUG "usbin_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-       }
-       spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbin_start(struct usb_audiodev *as)
-{
-       struct usb_device *dev = as->state->usbdev;
-       struct usbin *u = &as->usbin;
-       struct urb *urb;
-       unsigned long flags;
-       unsigned int maxsze, bufsz;
-
-#if 0
-       printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
-              dev->devnum, u->format, u->dma.format, u->dma.srate);
-#endif
-       /* allocate USB storage if not already done */
-       spin_lock_irqsave(&as->lock, flags);
-       if (!(u->flags & FLG_CONNECTED)) {
-               spin_unlock_irqrestore(&as->lock, flags);
-               return -EIO;
-       }
-       if (!(u->flags & FLG_RUNNING)) {
-               spin_unlock_irqrestore(&as->lock, flags);
-               u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
-               u->freqmax = u->freqn + (u->freqn >> 2);
-               u->phase = 0;
-               maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-               bufsz = DESCFRAMES * maxsze;
-               kfree(u->durb[0].urb->transfer_buffer);
-               u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-               u->durb[0].urb->transfer_buffer_length = bufsz;
-               kfree(u->durb[1].urb->transfer_buffer);
-               u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-               u->durb[1].urb->transfer_buffer_length = bufsz;
-               if (u->syncpipe) {
-                       kfree(u->surb[0].urb->transfer_buffer);
-                       u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-                       u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
-                       kfree(u->surb[1].urb->transfer_buffer);
-                       u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-                       u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
-               }
-               if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
-                   (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
-                       printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
-                       return 0;
-               }
-               spin_lock_irqsave(&as->lock, flags);
-       }
-       if (u->dma.count >= u->dma.dmasize && !u->dma.mapped) {
-               spin_unlock_irqrestore(&as->lock, flags);
-               return 0;
-       }
-       u->flags |= FLG_RUNNING;
-       if (!(u->flags & FLG_URB0RUNNING)) {
-               urb = u->durb[0].urb;
-               urb->dev = dev;
-               urb->pipe = u->datapipe;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = DESCFRAMES;
-               urb->context = as;
-               urb->complete = usbin_completed;
-               if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-                       u->flags |= FLG_URB0RUNNING;
-               else
-                       u->flags &= ~FLG_RUNNING;
-       }
-       if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-               urb = u->durb[1].urb;
-               urb->dev = dev;
-               urb->pipe = u->datapipe;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = DESCFRAMES;
-               urb->context = as;
-               urb->complete = usbin_completed;
-               if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-                       u->flags |= FLG_URB1RUNNING;
-               else
-                       u->flags &= ~FLG_RUNNING;
-       }
-       if (u->syncpipe) {
-               if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-                       urb = u->surb[0].urb;
-                       urb->dev = dev;
-                       urb->pipe = u->syncpipe;
-                       urb->transfer_flags = URB_ISO_ASAP;
-                       urb->number_of_packets = SYNCFRAMES;
-                       urb->context = as;
-                       urb->complete = usbin_sync_completed;
-                       /* stride: u->syncinterval */
-                       if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-                               u->flags |= FLG_SYNC0RUNNING;
-                       else
-                               u->flags &= ~FLG_RUNNING;
-               }
-               if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-                       urb = u->surb[1].urb;
-                       urb->dev = dev;
-                       urb->pipe = u->syncpipe;
-                       urb->transfer_flags = URB_ISO_ASAP;
-                       urb->number_of_packets = SYNCFRAMES;
-                       urb->context = as;
-                       urb->complete = usbin_sync_completed;
-                       /* stride: u->syncinterval */
-                       if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-                               u->flags |= FLG_SYNC1RUNNING;
-                       else
-                               u->flags &= ~FLG_RUNNING;
-               }
-       }
-       spin_unlock_irqrestore(&as->lock, flags);
-       return 0;
-}
-
-static void usbout_stop(struct usb_audiodev *as)
-{
-       struct usbout *u = &as->usbout;
-       unsigned long flags;
-       unsigned int i, notkilled = 1;
-
-       spin_lock_irqsave(&as->lock, flags);
-       u->flags &= ~FLG_RUNNING;
-       i = u->flags;
-       spin_unlock_irqrestore(&as->lock, flags);
-       while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-               if (notkilled)
-                       schedule_timeout_interruptible(1);
-               else
-                       schedule_timeout_uninterruptible(1);
-               spin_lock_irqsave(&as->lock, flags);
-               i = u->flags;
-               spin_unlock_irqrestore(&as->lock, flags);
-               if (notkilled && signal_pending(current)) {
-                       if (i & FLG_URB0RUNNING)
-                               usb_kill_urb(u->durb[0].urb);
-                       if (i & FLG_URB1RUNNING)
-                               usb_kill_urb(u->durb[1].urb);
-                       if (i & FLG_SYNC0RUNNING)
-                               usb_kill_urb(u->surb[0].urb);
-                       if (i & FLG_SYNC1RUNNING)
-                               usb_kill_urb(u->surb[1].urb);
-                       notkilled = 0;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       kfree(u->durb[0].urb->transfer_buffer);
-       kfree(u->durb[1].urb->transfer_buffer);
-       kfree(u->surb[0].urb->transfer_buffer);
-       kfree(u->surb[1].urb->transfer_buffer);
-       u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
-               u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
-}
-
-static inline void usbout_release(struct usb_audiodev *as)
-{
-       usbout_stop(as);
-}
-
-static void usbout_disc(struct usb_audiodev *as)
-{
-       struct usbout *u = &as->usbout;
-       unsigned long flags;
-
-       spin_lock_irqsave(&as->lock, flags);
-       u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);
-       spin_unlock_irqrestore(&as->lock, flags);
-       usbout_stop(as);
-}
-
-static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
-{
-       union {
-               __s16 s[64];
-               unsigned char b[0];
-       } tmp;
-       unsigned int scnt, maxs, ufmtsh, dfmtsh;
-
-       ufmtsh = AFMT_BYTESSHIFT(u->format);
-       dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-       maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
-       while (samples > 0) {
-               scnt = samples;
-               if (scnt > maxs)
-                       scnt = maxs;
-               dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
-               conversion(tmp.b, u->dma.format, buffer, u->format, tmp.b, scnt);
-               buffer += scnt << ufmtsh;
-               samples -= scnt;
-       }
-}              
-
-static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
-{
-       unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
-       unsigned char *cp = urb->transfer_buffer;
-
-       ufmtsh = AFMT_BYTESSHIFT(u->format);
-       dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-       for (i = offs = 0; i < DESCFRAMES; i++) {
-               urb->iso_frame_desc[i].offset = offs;
-               u->phase = (u->phase & 0x3fff) + u->freqm;
-               scnt = u->phase >> 14;
-               if (!scnt) {
-                       urb->iso_frame_desc[i].length = 0;
-                       continue;
-               }
-               cnt = scnt << dfmtsh;
-               if (!u->dma.mapped) {
-                       if (cnt > u->dma.count) {
-                               scnt = u->dma.count >> dfmtsh;
-                               cnt = scnt << dfmtsh;
-                               err++;
-                       }
-                       u->dma.count -= cnt;
-               } else
-                       u->dma.count += cnt;
-               if (u->format == u->dma.format) {
-                       /* we do not need format conversion */
-                       dmabuf_copyout(&u->dma, cp, cnt);
-               } else {
-                       /* we need sampling format conversion */
-                       usbout_convert(u, cp, scnt);
-               }
-               cnt = scnt << ufmtsh;
-               urb->iso_frame_desc[i].length = cnt;
-               offs += cnt;
-               cp += cnt;
-       }
-       urb->interval = 1;
-       if (err)
-               u->dma.error++;
-       if (u->dma.mapped) {
-               if (u->dma.count >= (signed)u->dma.fragsize)
-                       wake_up(&u->dma.wait);
-       } else {
-               if ((signed)u->dma.dmasize >= u->dma.count + (signed)u->dma.fragsize)
-                       wake_up(&u->dma.wait);
-       }
-       return err ? -1 : 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbout_retire_desc(struct usbout *u, struct urb *urb)
-{
-       unsigned int i;
-
-       for (i = 0; i < DESCFRAMES; i++) {
-               if (urb->iso_frame_desc[i].status) {
-                       dprintk((KERN_DEBUG "usbout_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-                       continue;
-               }
-       }
-       return 0;
-}
-
-static void usbout_completed(struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-       struct usbout *u = &as->usbout;
-       unsigned long flags;
-       unsigned int mask;
-       int suret = 0;
-
-#if 0
-       printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-       if (urb == u->durb[0].urb)
-               mask = FLG_URB0RUNNING;
-       else if (urb == u->durb[1].urb)
-               mask = FLG_URB1RUNNING;
-       else {
-               mask = 0;
-               printk(KERN_ERR "usbout_completed: panic: unknown URB\n");
-       }
-       urb->dev = as->state->usbdev;
-       spin_lock_irqsave(&as->lock, flags);
-       if (!usbout_retire_desc(u, urb) &&
-           u->flags & FLG_RUNNING &&
-           !usbout_prepare_desc(u, urb) && 
-           (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-               u->flags |= mask;
-       } else {
-               u->flags &= ~(mask | FLG_RUNNING);
-               wake_up(&u->dma.wait);
-               dprintk((KERN_DEBUG "usbout_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-       }
-       spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
-{
-       unsigned int i, offs;
-
-       for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3) {
-               urb->iso_frame_desc[i].length = 3;
-               urb->iso_frame_desc[i].offset = offs;
-       }
-       urb->interval = 1;
-       return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
-{
-       unsigned char *cp = urb->transfer_buffer;
-       unsigned int f, i;
-
-       for (i = 0; i < SYNCFRAMES; i++, cp += 3) {
-               if (urb->iso_frame_desc[i].status) {
-                       dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-                       continue;
-               }
-               if (urb->iso_frame_desc[i].actual_length < 3) {
-                       dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u length %d\n", i, urb->iso_frame_desc[i].actual_length));
-                       continue;
-               }
-               f = cp[0] | (cp[1] << 8) | (cp[2] << 16);
-               if (abs(f - u->freqn) > (u->freqn >> 3) || f > u->freqmax) {
-                       printk(KERN_WARNING "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n", f, u->freqn);
-                       continue;
-               }
-               u->freqm = f;
-       }
-       return 0;
-}
-
-static void usbout_sync_completed(struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-       struct usbout *u = &as->usbout;
-       unsigned long flags;
-       unsigned int mask;
-       int suret = 0;
-
-#if 0
-       printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-       if (urb == u->surb[0].urb)
-               mask = FLG_SYNC0RUNNING;
-       else if (urb == u->surb[1].urb)
-               mask = FLG_SYNC1RUNNING;
-       else {
-               mask = 0;
-               printk(KERN_ERR "usbout_sync_completed: panic: unknown URB\n");
-       }
-       urb->dev = as->state->usbdev;
-       spin_lock_irqsave(&as->lock, flags);
-       if (!usbout_sync_retire_desc(u, urb) &&
-           u->flags & FLG_RUNNING &&
-           !usbout_sync_prepare_desc(u, urb) && 
-           (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-               u->flags |= mask;
-       } else {
-               u->flags &= ~(mask | FLG_RUNNING);
-               wake_up(&u->dma.wait);
-               dprintk((KERN_DEBUG "usbout_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-       }
-       spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbout_start(struct usb_audiodev *as)
-{
-       struct usb_device *dev = as->state->usbdev;
-       struct usbout *u = &as->usbout;
-       struct urb *urb;
-       unsigned long flags;
-       unsigned int maxsze, bufsz;
-
-#if 0
-       printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
-              dev->devnum, u->format, u->dma.format, u->dma.srate);
-#endif
-       /* allocate USB storage if not already done */
-       spin_lock_irqsave(&as->lock, flags);
-       if (!(u->flags & FLG_CONNECTED)) {
-               spin_unlock_irqrestore(&as->lock, flags);
-               return -EIO;
-       }
-       if (!(u->flags & FLG_RUNNING)) {
-               spin_unlock_irqrestore(&as->lock, flags);
-               u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
-               u->freqmax = u->freqn + (u->freqn >> 2);
-               u->phase = 0;
-               maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-               bufsz = DESCFRAMES * maxsze;
-               kfree(u->durb[0].urb->transfer_buffer);
-               u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-               u->durb[0].urb->transfer_buffer_length = bufsz;
-               kfree(u->durb[1].urb->transfer_buffer);
-               u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-               u->durb[1].urb->transfer_buffer_length = bufsz;
-               if (u->syncpipe) {
-                       kfree(u->surb[0].urb->transfer_buffer);
-                       u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-                       u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
-                       kfree(u->surb[1].urb->transfer_buffer);
-                       u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-                       u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
-               }
-               if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
-                   (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
-                       printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
-                       return 0;
-               }
-               spin_lock_irqsave(&as->lock, flags);
-       }
-       if (u->dma.count <= 0 && !u->dma.mapped) {
-               spin_unlock_irqrestore(&as->lock, flags);
-               return 0;
-       }
-               u->flags |= FLG_RUNNING;
-       if (!(u->flags & FLG_URB0RUNNING)) {
-               urb = u->durb[0].urb;
-               urb->dev = dev;
-               urb->pipe = u->datapipe;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = DESCFRAMES;
-               urb->context = as;
-               urb->complete = usbout_completed;
-               if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-                       u->flags |= FLG_URB0RUNNING;
-               else
-                       u->flags &= ~FLG_RUNNING;
-       }
-       if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-               urb = u->durb[1].urb;
-               urb->dev = dev;
-               urb->pipe = u->datapipe;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = DESCFRAMES;
-               urb->context = as;
-               urb->complete = usbout_completed;
-               if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-                       u->flags |= FLG_URB1RUNNING;
-               else
-                       u->flags &= ~FLG_RUNNING;
-       }
-       if (u->syncpipe) {
-               if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-                       urb = u->surb[0].urb;
-                       urb->dev = dev;
-                       urb->pipe = u->syncpipe;
-                       urb->transfer_flags = URB_ISO_ASAP;
-                       urb->number_of_packets = SYNCFRAMES;
-                       urb->context = as;
-                       urb->complete = usbout_sync_completed;
-                       /* stride: u->syncinterval */
-                       if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-                               u->flags |= FLG_SYNC0RUNNING;
-                       else
-                               u->flags &= ~FLG_RUNNING;
-               }
-               if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-                       urb = u->surb[1].urb;
-                       urb->dev = dev;
-                       urb->pipe = u->syncpipe;
-                       urb->transfer_flags = URB_ISO_ASAP;
-                       urb->number_of_packets = SYNCFRAMES;
-                       urb->context = as;
-                       urb->complete = usbout_sync_completed;
-                       /* stride: u->syncinterval */
-                       if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-                               u->flags |= FLG_SYNC1RUNNING;
-                       else
-                               u->flags &= ~FLG_RUNNING;
-               }
-       }
-       spin_unlock_irqrestore(&as->lock, flags);
-       return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate)
-{
-       unsigned int g = 0;
-
-       if (srate < afp->sratelo)
-               g += afp->sratelo - srate;
-       if (srate > afp->sratehi)
-               g += srate - afp->sratehi;
-       if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt))
-               g += 0x100000;
-       if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt))
-               g += 0x400000;
-       if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt))
-               g += 0x100000;
-       if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt))
-               g += 0x400000;
-       return g;
-}
-
-static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate)
-{
-       unsigned int i, g, gb = ~0;
-       int j = -1; /* default to failure */
-
-       /* find "best" format (according to format_goodness) */
-       for (i = 0; i < nr; i++) {
-               g = format_goodness(&afp[i], fmt, srate);
-               if (g >= gb) 
-                       continue;
-               j = i;
-               gb = g;
-       }
-               return j;
-}
-
-static int set_format_in(struct usb_audiodev *as)
-{
-       struct usb_device *dev = as->state->usbdev;
-       struct usb_host_interface *alts;
-       struct usb_interface *iface;
-       struct usbin *u = &as->usbin;
-       struct dmabuf *d = &u->dma;
-       struct audioformat *fmt;
-       unsigned int ep;
-       unsigned char data[3];
-       int fmtnr, ret;
-
-       iface = usb_ifnum_to_if(dev, u->interface);
-       if (!iface)
-               return 0;
-
-       fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
-       if (fmtnr < 0) {
-               printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n");
-               return -1;
-       }
-
-       fmt = as->fmtin + fmtnr;
-       alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
-       u->format = fmt->format;
-       u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
-       u->syncpipe = u->syncinterval = 0;
-       if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x08) {
-               if (alts->desc.bNumEndpoints < 2 ||
-                   alts->endpoint[1].desc.bmAttributes != 0x01 ||
-                   alts->endpoint[1].desc.bSynchAddress != 0 ||
-                   alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) {
-                       printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in "
-                              "but has invalid synch pipe; treating as asynchronous in\n",
-                              dev->devnum, u->interface, fmt->altsetting);
-               } else {
-                       u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
-                       u->syncinterval = alts->endpoint[1].desc.bRefresh;
-               }
-       }
-       if (d->srate < fmt->sratelo)
-               d->srate = fmt->sratelo;
-       if (d->srate > fmt->sratehi)
-               d->srate = fmt->sratehi;
-       dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n",
-                       u->interface, fmt->altsetting));
-       if (usb_set_interface(dev, alts->desc.bInterfaceNumber, fmt->altsetting) < 0) {
-               printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
-                      dev->devnum, u->interface, fmt->altsetting);
-               return -1;
-       }
-       if (fmt->sratelo == fmt->sratehi)
-               return 0;
-       ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
-       /* if endpoint has pitch control, enable it */
-       if (fmt->attributes & 0x02) {
-               data[0] = 1;
-               if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-                                          PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
-                       printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
-                              ret, dev->devnum, u->interface, ep, d->srate);
-                       return -1;
-               }
-       }
-       /* if endpoint has sampling rate control, set it */
-       if (fmt->attributes & 0x01) {
-               data[0] = d->srate;
-               data[1] = d->srate >> 8;
-               data[2] = d->srate >> 16;
-               if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-                                          SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-                       printk(KERN_ERR "usbaudio: failure (error %d) to set input sampling frequency device %d interface %u endpoint 0x%x to %u\n",
-                              ret, dev->devnum, u->interface, ep, d->srate);
-                       return -1;
-               }
-               if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-                                          SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-                       printk(KERN_ERR "usbaudio: failure (error %d) to get input sampling frequency device %d interface %u endpoint 0x%x\n",
-                              ret, dev->devnum, u->interface, ep);
-                       return -1;
-               }
-               dprintk((KERN_DEBUG "usbaudio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n",
-                       dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
-               d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
-       }
-       dprintk((KERN_DEBUG "usbaudio: set_format_in: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate));
-       return 0;
-}
-
-static int set_format_out(struct usb_audiodev *as)
-{
-       struct usb_device *dev = as->state->usbdev;
-       struct usb_host_interface *alts;
-       struct usb_interface *iface;    
-       struct usbout *u = &as->usbout;
-       struct dmabuf *d = &u->dma;
-       struct audioformat *fmt;
-       unsigned int ep;
-       unsigned char data[3];
-       int fmtnr, ret;
-
-       iface = usb_ifnum_to_if(dev, u->interface);
-       if (!iface)
-               return 0;
-
-       fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
-       if (fmtnr < 0) {
-               printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n");
-               return -1;
-       }
-
-       fmt = as->fmtout + fmtnr;
-       u->format = fmt->format;
-       alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
-       u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
-       u->syncpipe = u->syncinterval = 0;
-       if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x04) {
-#if 0
-               printk(KERN_DEBUG "bNumEndpoints 0x%02x endpoint[1].bmAttributes 0x%02x\n"
-                      KERN_DEBUG "endpoint[1].bSynchAddress 0x%02x endpoint[1].bEndpointAddress 0x%02x\n"
-                      KERN_DEBUG "endpoint[0].bSynchAddress 0x%02x\n", alts->bNumEndpoints,
-                      alts->endpoint[1].bmAttributes, alts->endpoint[1].bSynchAddress,
-                      alts->endpoint[1].bEndpointAddress, alts->endpoint[0].bSynchAddress);
-#endif
-               if (alts->desc.bNumEndpoints < 2 ||
-                   alts->endpoint[1].desc.bmAttributes != 0x01 ||
-                   alts->endpoint[1].desc.bSynchAddress != 0 ||
-                   alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress | 0x80)) {
-                       printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out "
-                              "but has invalid synch pipe; treating as adaptive out\n",
-                              dev->devnum, u->interface, fmt->altsetting);
-               } else {
-                       u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
-                       u->syncinterval = alts->endpoint[1].desc.bRefresh;
-               }
-       }
-       if (d->srate < fmt->sratelo)
-               d->srate = fmt->sratelo;
-       if (d->srate > fmt->sratehi)
-               d->srate = fmt->sratehi;
-       dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n",
-                       u->interface, fmt->altsetting));
-       if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
-               printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
-                      dev->devnum, u->interface, fmt->altsetting);
-               return -1;
-       }
-       if (fmt->sratelo == fmt->sratehi)
-               return 0;
-       ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
-       /* if endpoint has pitch control, enable it */
-       if (fmt->attributes & 0x02) {
-               data[0] = 1;
-               if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-                                          PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
-                       printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
-                              ret, dev->devnum, u->interface, ep, d->srate);
-                       return -1;
-               }
-       }
-       /* if endpoint has sampling rate control, set it */
-       if (fmt->attributes & 0x01) {
-               data[0] = d->srate;
-               data[1] = d->srate >> 8;
-               data[2] = d->srate >> 16;
-               if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-                                          SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-                       printk(KERN_ERR "usbaudio: failure (error %d) to set output sampling frequency device %d interface %u endpoint 0x%x to %u\n",
-                              ret, dev->devnum, u->interface, ep, d->srate);
-                       return -1;
-               }
-               if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-                                          SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-                       printk(KERN_ERR "usbaudio: failure (error %d) to get output sampling frequency device %d interface %u endpoint 0x%x\n",
-                              ret, dev->devnum, u->interface, ep);
-                       return -1;
-               }
-               dprintk((KERN_DEBUG "usbaudio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n",
-                       dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
-               d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
-       }
-       dprintk((KERN_DEBUG "usbaudio: set_format_out: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate));
-       return 0;
-}
-
-static int set_format(struct usb_audiodev *s, unsigned int fmode, unsigned int fmt, unsigned int srate)
-{
-       int ret1 = 0, ret2 = 0;
-
-       if (!(fmode & (FMODE_READ|FMODE_WRITE)))
-               return -EINVAL;
-       if (fmode & FMODE_READ) {
-               usbin_stop(s);
-               s->usbin.dma.ready = 0;
-               if (fmt == AFMT_QUERY)
-                       fmt = s->usbin.dma.format;
-               else
-                       s->usbin.dma.format = fmt;
-               if (!srate)
-                       srate = s->usbin.dma.srate;
-               else
-                       s->usbin.dma.srate = srate;
-       }
-       if (fmode & FMODE_WRITE) {
-               usbout_stop(s);
-               s->usbout.dma.ready = 0;
-               if (fmt == AFMT_QUERY)
-                       fmt = s->usbout.dma.format;
-               else
-                       s->usbout.dma.format = fmt;
-               if (!srate)
-                       srate = s->usbout.dma.srate;
-               else
-                       s->usbout.dma.srate = srate;
-       }
-       if (fmode & FMODE_READ)
-               ret1 = set_format_in(s);
-       if (fmode & FMODE_WRITE)
-               ret2 = set_format_out(s);
-       return ret1 ? ret1 : ret2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
-{
-       struct usb_device *dev = ms->state->usbdev;
-       unsigned char data[2];
-       struct mixerchannel *ch;
-       int v1, v2, v3;
-
-       if (mixch >= ms->numch)
-               return -1;
-       ch = &ms->ch[mixch];
-       v3 = ch->maxval - ch->minval;
-       v1 = value & 0xff;
-       v2 = (value >> 8) & 0xff;
-       if (v1 > 100)
-               v1 = 100;
-       if (v2 > 100)
-               v2 = 100;
-       if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-               v2 = v1;
-       ch->value = v1 | (v2 << 8);
-       v1 = (v1 * v3) / 100 + ch->minval;
-       v2 = (v2 * v3) / 100 + ch->minval;
-       switch (ch->selector) {
-       case 0:  /* mixer unit request */
-               data[0] = v1;
-               data[1] = v1 >> 8;
-               if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-                       goto err;
-               if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-                       return 0;
-               data[0] = v2;
-               data[1] = v2 >> 8;
-               if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-                                   ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-                       goto err;
-               return 0;
-
-               /* various feature unit controls */
-       case VOLUME_CONTROL:
-               data[0] = v1;
-               data[1] = v1 >> 8;
-               if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-                       goto err;
-               if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-                       return 0;
-               data[0] = v2;
-               data[1] = v2 >> 8;
-               if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-                       goto err;
-               return 0;
-                
-       case BASS_CONTROL:
-       case MID_CONTROL:
-       case TREBLE_CONTROL:
-               data[0] = v1 >> 8;
-               if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
-                       goto err;
-               if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-                       return 0;
-               data[0] = v2 >> 8;
-               if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
-                       goto err;
-               return 0;
-
-       default:
-               return -1;
-       }
-       return 0;
-
- err:
-       printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
-               dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
-       return -1;
-}
-
-static int get_rec_src(struct usb_mixerdev *ms)
-{
-       struct usb_device *dev = ms->state->usbdev;
-       unsigned int mask = 0, retmask = 0;
-       unsigned int i, j;
-       unsigned char buf;
-       int err = 0;
-
-       for (i = 0; i < ms->numch; i++) {
-               if (!ms->ch[i].slctunitid || (mask & (1 << i)))
-                       continue;
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
-                       err = -EIO;
-                       printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
-                              dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
-                       continue;
-               }
-               for (j = i; j < ms->numch; j++) {
-                       if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-                               continue;
-                       mask |= 1 << j;
-                       if (buf == (ms->ch[j].slctunitid >> 8))
-                               retmask |= 1 << ms->ch[j].osschannel;
-               }
-       }
-       if (err)
-               return -EIO;
-       return retmask;
-}
-
-static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
-{
-       struct usb_device *dev = ms->state->usbdev;
-       unsigned int mask = 0, smask, bmask;
-       unsigned int i, j;
-       unsigned char buf;
-       int err = 0;
-
-       for (i = 0; i < ms->numch; i++) {
-               if (!ms->ch[i].slctunitid || (mask & (1 << i)))
-                       continue;
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
-                       err = -EIO;
-                       printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
-                              dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
-                       continue;
-               }
-               /* first generate smask */
-               smask = bmask = 0;
-               for (j = i; j < ms->numch; j++) {
-                       if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-                               continue;
-                       smask |= 1 << ms->ch[j].osschannel;
-                       if (buf == (ms->ch[j].slctunitid >> 8))
-                               bmask |= 1 << ms->ch[j].osschannel;
-                       mask |= 1 << j;
-               }
-               /* check for multiple set sources */
-               j = hweight32(srcmask & smask);
-               if (j == 0)
-                       continue;
-               if (j > 1)
-                       srcmask &= ~bmask;
-               for (j = i; j < ms->numch; j++) {
-                       if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-                               continue;
-                       if (!(srcmask & (1 << ms->ch[j].osschannel)))
-                               continue;
-                       buf = ms->ch[j].slctunitid >> 8;
-                       if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, 1000) < 0) {
-                               err = -EIO;
-                               printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n", 
-                                      dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
-                               continue;
-                       }
-               }
-       }
-       return err ? -EIO : 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * should be called with open_sem hold, so that no new processes
- * look at the audio device to be destroyed
- */
-
-static void release(struct usb_audio_state *s)
-{
-       struct usb_audiodev *as;
-       struct usb_mixerdev *ms;
-
-       s->count--;
-       if (s->count) {
-               up(&open_sem);
-               return;
-       }
-       up(&open_sem);
-       wake_up(&open_wait);
-       while (!list_empty(&s->audiolist)) {
-               as = list_entry(s->audiolist.next, struct usb_audiodev, list);
-               list_del(&as->list);
-               usbin_release(as);
-               usbout_release(as);
-               dmabuf_release(&as->usbin.dma);
-               dmabuf_release(&as->usbout.dma);
-               usb_free_urb(as->usbin.durb[0].urb);
-               usb_free_urb(as->usbin.durb[1].urb);
-               usb_free_urb(as->usbin.surb[0].urb);
-               usb_free_urb(as->usbin.surb[1].urb);
-               usb_free_urb(as->usbout.durb[0].urb);
-               usb_free_urb(as->usbout.durb[1].urb);
-               usb_free_urb(as->usbout.surb[0].urb);
-               usb_free_urb(as->usbout.surb[1].urb);
-               kfree(as);
-       }
-       while (!list_empty(&s->mixerlist)) {
-               ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list);
-               list_del(&ms->list);
-               kfree(ms);
-       }
-       kfree(s);
-}
-
-static inline int prog_dmabuf_in(struct usb_audiodev *as)
-{
-       usbin_stop(as);
-       return dmabuf_init(&as->usbin.dma);
-}
-
-static inline int prog_dmabuf_out(struct usb_audiodev *as)
-{
-       usbout_stop(as);
-       return dmabuf_init(&as->usbout.dma);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
-{
-       unsigned int minor = iminor(inode);
-       struct usb_mixerdev *ms;
-       struct usb_audio_state *s;
-
-       down(&open_sem);
-       list_for_each_entry(s, &audiodevs, audiodev) {
-               list_for_each_entry(ms, &s->mixerlist, list) {
-                       if (ms->dev_mixer == minor)
-                               goto mixer_found;
-               }
-       }
-       up(&open_sem);
-       return -ENODEV;
-
- mixer_found:
-       if (!s->usbdev) {
-               up(&open_sem);
-               return -EIO;
-       }
-       file->private_data = ms;
-       s->count++;
-
-       up(&open_sem);
-       return nonseekable_open(inode, file);
-}
-
-static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
-{
-       struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
-       struct usb_audio_state *s;
-
-       lock_kernel();
-       s = ms->state;
-       down(&open_sem);
-       release(s);
-       unlock_kernel();
-       return 0;
-}
-
-static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
-       int i, j, val;
-       int __user *user_arg = (int __user *)arg;
-
-       if (!ms->state->usbdev)
-               return -ENODEV;
-  
-       if (cmd == SOUND_MIXER_INFO) {
-               mixer_info info;
-
-               memset(&info, 0, sizeof(info));
-               strncpy(info.id, "USB_AUDIO", sizeof(info.id));
-               strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
-               info.modify_counter = ms->modcnt;
-               if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == SOUND_OLD_MIXER_INFO) {
-               _old_mixer_info info;
-
-               memset(&info, 0, sizeof(info));
-               strncpy(info.id, "USB_AUDIO", sizeof(info.id));
-               strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
-               if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, user_arg);
-       if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
-               return -EINVAL;
-       if (_IOC_DIR(cmd) == _IOC_READ) {
-               switch (_IOC_NR(cmd)) {
-               case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-                       val = get_rec_src(ms);
-                       if (val < 0)
-                               return val;
-                       return put_user(val, user_arg);
-
-               case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-                       for (val = i = 0; i < ms->numch; i++)
-                               val |= 1 << ms->ch[i].osschannel;
-                       return put_user(val, user_arg);
-
-               case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-                       for (val = i = 0; i < ms->numch; i++)
-                               if (ms->ch[i].slctunitid)
-                                       val |= 1 << ms->ch[i].osschannel;
-                       return put_user(val, user_arg);
-
-               case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-                       for (val = i = 0; i < ms->numch; i++)
-                               if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
-                                       val |= 1 << ms->ch[i].osschannel;
-                       return put_user(val, user_arg);
-                       
-               case SOUND_MIXER_CAPS:
-                       return put_user(SOUND_CAP_EXCL_INPUT, user_arg);
-
-               default:
-                       i = _IOC_NR(cmd);
-                       if (i >= SOUND_MIXER_NRDEVICES)
-                               return -EINVAL;
-                       for (j = 0; j < ms->numch; j++) {
-                               if (ms->ch[j].osschannel == i) {
-                                       return put_user(ms->ch[j].value, user_arg);
-                               }
-                       }
-                       return -EINVAL;
-               }
-       }
-       if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) 
-               return -EINVAL;
-       ms->modcnt++;
-       switch (_IOC_NR(cmd)) {
-       case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               return set_rec_src(ms, val);
-
-       default:
-               i = _IOC_NR(cmd);
-               if (i >= SOUND_MIXER_NRDEVICES)
-                       return -EINVAL;
-               for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++);
-               if (j >= ms->numch)
-                       return -EINVAL;
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               if (wrmixer(ms, j, val))
-                       return -EIO;
-               return put_user(ms->ch[j].value, user_arg);
-       }
-}
-
-static /*const*/ struct file_operations usb_mixer_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .ioctl =        usb_audio_ioctl_mixdev,
-       .open =         usb_audio_open_mixdev,
-       .release =      usb_audio_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_out(struct usb_audiodev *as, int nonblock)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       unsigned long flags;
-       int count, tmo;
-       
-       if (as->usbout.dma.mapped || !as->usbout.dma.ready)
-               return 0;
-       usbout_start(as);
-       add_wait_queue(&as->usbout.dma.wait, &wait);
-       for (;;) {
-               __set_current_state(TASK_INTERRUPTIBLE);
-               spin_lock_irqsave(&as->lock, flags);
-               count = as->usbout.dma.count;
-               spin_unlock_irqrestore(&as->lock, flags);
-               if (count <= 0)
-                       break;
-               if (signal_pending(current))
-                       break;
-               if (nonblock) {
-                       remove_wait_queue(&as->usbout.dma.wait, &wait);
-                       set_current_state(TASK_RUNNING);
-                       return -EBUSY;
-               }
-               tmo = 3 * HZ * count / as->usbout.dma.srate;
-               tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
-               if (!schedule_timeout(tmo + 1)) {
-                       printk(KERN_DEBUG "usbaudio: dma timed out??\n");
-                       break;
-               }
-       }
-       remove_wait_queue(&as->usbout.dma.wait, &wait);
-       set_current_state(TASK_RUNNING);
-       if (signal_pending(current))
-               return -ERESTARTSYS;
-       return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t usb_audio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-       DECLARE_WAITQUEUE(wait, current);
-       ssize_t ret = 0;
-       unsigned long flags;
-       unsigned int ptr;
-       int cnt, err;
-
-       if (as->usbin.dma.mapped)
-               return -ENXIO;
-       if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
-               return ret;
-       if (!access_ok(VERIFY_WRITE, buffer, count))
-               return -EFAULT;
-       add_wait_queue(&as->usbin.dma.wait, &wait);
-       while (count > 0) {
-               spin_lock_irqsave(&as->lock, flags);
-               ptr = as->usbin.dma.rdptr;
-               cnt = as->usbin.dma.count;
-               /* set task state early to avoid wakeup races */
-               if (cnt <= 0)
-                       __set_current_state(TASK_INTERRUPTIBLE);
-               spin_unlock_irqrestore(&as->lock, flags);
-               if (cnt > count)
-                       cnt = count;
-               if (cnt <= 0) {
-                       if (usbin_start(as)) {
-                               if (!ret)
-                                       ret = -ENODEV;
-                               break;
-                       }
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret)
-                                       ret = -EAGAIN;
-                               break;
-                       }
-                       schedule();
-                       if (signal_pending(current)) {
-                               if (!ret)
-                                       ret = -ERESTARTSYS;
-                               break;
-                       }
-                       continue;
-               }
-               if ((err = dmabuf_copyout_user(&as->usbin.dma, ptr, buffer, cnt))) {
-                       if (!ret)
-                               ret = err;
-                       break;
-               }
-               ptr += cnt;
-               if (ptr >= as->usbin.dma.dmasize)
-                       ptr -= as->usbin.dma.dmasize;
-               spin_lock_irqsave(&as->lock, flags);
-               as->usbin.dma.rdptr = ptr;
-               as->usbin.dma.count -= cnt;
-               spin_unlock_irqrestore(&as->lock, flags);
-               count -= cnt;
-               buffer += cnt;
-               ret += cnt;
-       }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&as->usbin.dma.wait, &wait);
-       return ret;
-}
-
-static ssize_t usb_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-       DECLARE_WAITQUEUE(wait, current);
-       ssize_t ret = 0;
-       unsigned long flags;
-       unsigned int ptr;
-       unsigned int start_thr;
-       int cnt, err;
-
-       if (as->usbout.dma.mapped)
-               return -ENXIO;
-       if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
-               return ret;
-       if (!access_ok(VERIFY_READ, buffer, count))
-               return -EFAULT;
-       start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
-       add_wait_queue(&as->usbout.dma.wait, &wait);
-       while (count > 0) {
-#if 0
-               printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%lx\n",
-                      count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize,
-                      as->usbout.flags, current->state);
-#endif
-               spin_lock_irqsave(&as->lock, flags);
-               if (as->usbout.dma.count < 0) {
-                       as->usbout.dma.count = 0;
-                       as->usbout.dma.rdptr = as->usbout.dma.wrptr;
-               }
-               ptr = as->usbout.dma.wrptr;
-               cnt = as->usbout.dma.dmasize - as->usbout.dma.count;
-               /* set task state early to avoid wakeup races */
-               if (cnt <= 0)
-                       __set_current_state(TASK_INTERRUPTIBLE);
-               spin_unlock_irqrestore(&as->lock, flags);
-               if (cnt > count)
-                       cnt = count;
-               if (cnt <= 0) {
-                       if (usbout_start(as)) {
-                               if (!ret)
-                                       ret = -ENODEV;
-                               break;
-                       }
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret)
-                                       ret = -EAGAIN;
-                               break;
-                       }
-                       schedule();
-                       if (signal_pending(current)) {
-                               if (!ret)
-                                       ret = -ERESTARTSYS;
-                               break;
-                       }
-                       continue;
-               }
-               if ((err = dmabuf_copyin_user(&as->usbout.dma, ptr, buffer, cnt))) {
-                       if (!ret)
-                               ret = err;
-                       break;
-               }
-               ptr += cnt;
-               if (ptr >= as->usbout.dma.dmasize)
-                       ptr -= as->usbout.dma.dmasize;
-               spin_lock_irqsave(&as->lock, flags);
-               as->usbout.dma.wrptr = ptr;
-               as->usbout.dma.count += cnt;
-               spin_unlock_irqrestore(&as->lock, flags);
-               count -= cnt;
-               buffer += cnt;
-               ret += cnt;
-               if (as->usbout.dma.count >= start_thr && usbout_start(as)) {
-                       if (!ret)
-                               ret = -ENODEV;
-                       break;
-               }
-       }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&as->usbout.dma.wait, &wait);
-       return ret;
-}
-
-/* Called without the kernel lock - fine */
-static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-       unsigned long flags;
-       unsigned int mask = 0;
-
-       if (file->f_mode & FMODE_WRITE) {
-               if (!as->usbout.dma.ready)
-                       prog_dmabuf_out(as);
-               poll_wait(file, &as->usbout.dma.wait, wait);
-       }
-       if (file->f_mode & FMODE_READ) {
-               if (!as->usbin.dma.ready)
-                       prog_dmabuf_in(as);
-               poll_wait(file, &as->usbin.dma.wait, wait);
-       }
-       spin_lock_irqsave(&as->lock, flags);
-       if (file->f_mode & FMODE_READ) {
-               if (as->usbin.dma.count >= (signed)as->usbin.dma.fragsize)
-                       mask |= POLLIN | POLLRDNORM;
-       }
-       if (file->f_mode & FMODE_WRITE) {
-               if (as->usbout.dma.mapped) {
-                       if (as->usbout.dma.count >= (signed)as->usbout.dma.fragsize) 
-                               mask |= POLLOUT | POLLWRNORM;
-               } else {
-                       if ((signed)as->usbout.dma.dmasize >= as->usbout.dma.count + (signed)as->usbout.dma.fragsize)
-                               mask |= POLLOUT | POLLWRNORM;
-               }
-       }
-       spin_unlock_irqrestore(&as->lock, flags);
-       return mask;
-}
-
-static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-       struct dmabuf *db;
-       int ret = -EINVAL;
-
-       lock_kernel();
-       if (vma->vm_flags & VM_WRITE) {
-               if ((ret = prog_dmabuf_out(as)) != 0)
-                       goto out;
-               db = &as->usbout.dma;
-       } else if (vma->vm_flags & VM_READ) {
-               if ((ret = prog_dmabuf_in(as)) != 0)
-                       goto out;
-               db = &as->usbin.dma;
-       } else
-               goto out;
-
-       ret = -EINVAL;
-       if (vma->vm_pgoff != 0)
-               goto out;
-
-       ret = dmabuf_mmap(vma, db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
-out:
-       unlock_kernel();
-       return ret;
-}
-
-static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-       struct usb_audio_state *s = as->state;
-       int __user *user_arg = (int __user *)arg;
-       unsigned long flags;
-       audio_buf_info abinfo;
-       count_info cinfo;
-       int val = 0;
-       int val2, mapped, ret;
-
-       if (!s->usbdev)
-               return -EIO;
-       mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) ||
-               ((file->f_mode & FMODE_READ) && as->usbin.dma.mapped);
-#if 0
-       if (arg)
-               get_user(val, (int *)arg);
-       printk(KERN_DEBUG "usbaudio: usb_audio_ioctl cmd=%x arg=%lx *arg=%d\n", cmd, arg, val)
-#endif
-       switch (cmd) {
-       case OSS_GETVERSION:
-               return put_user(SOUND_VERSION, user_arg);
-
-       case SNDCTL_DSP_SYNC:
-               if (file->f_mode & FMODE_WRITE)
-                       return drain_out(as, 0/*file->f_flags & O_NONBLOCK*/);
-               return 0;
-
-       case SNDCTL_DSP_SETDUPLEX:
-               return 0;
-
-       case SNDCTL_DSP_GETCAPS:
-               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | 
-                               DSP_CAP_MMAP | DSP_CAP_BATCH, user_arg);
-
-       case SNDCTL_DSP_RESET:
-               if (file->f_mode & FMODE_WRITE) {
-                       usbout_stop(as);
-                       as->usbout.dma.rdptr = as->usbout.dma.wrptr = as->usbout.dma.count = as->usbout.dma.total_bytes = 0;
-               }
-               if (file->f_mode & FMODE_READ) {
-                       usbin_stop(as);
-                       as->usbin.dma.rdptr = as->usbin.dma.wrptr = as->usbin.dma.count = as->usbin.dma.total_bytes = 0;
-               }
-               return 0;
-
-       case SNDCTL_DSP_SPEED:
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               if (val >= 0) {
-                       if (val < 4000)
-                               val = 4000;
-                       if (val > 100000)
-                               val = 100000;
-                       if (set_format(as, file->f_mode, AFMT_QUERY, val))
-                               return -EIO;
-               }
-               return put_user((file->f_mode & FMODE_READ) ? 
-                               as->usbin.dma.srate : as->usbout.dma.srate,
-                               user_arg);
-
-       case SNDCTL_DSP_STEREO:
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-               if (val)
-                       val2 |= AFMT_STEREO;
-               else
-                       val2 &= ~AFMT_STEREO;
-               if (set_format(as, file->f_mode, val2, 0))
-                       return -EIO;
-               return 0;
-
-       case SNDCTL_DSP_CHANNELS:
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               if (val != 0) {
-                       val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-                       if (val == 1)
-                               val2 &= ~AFMT_STEREO;
-                       else
-                               val2 |= AFMT_STEREO;
-                       if (set_format(as, file->f_mode, val2, 0))
-                               return -EIO;
-               }
-               val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-               return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg);
-
-       case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-               return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
-                               AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, user_arg);
-
-       case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               if (val != AFMT_QUERY) {
-                       if (hweight32(val) != 1)
-                               return -EINVAL;
-                       if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
-                                    AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
-                               return -EINVAL;
-                       val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-                       val |= val2 & AFMT_STEREO;
-                       if (set_format(as, file->f_mode, val, 0))
-                               return -EIO;
-               }
-               val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-               return put_user(val2 & ~AFMT_STEREO, user_arg);
-
-       case SNDCTL_DSP_POST:
-               return 0;
-
-       case SNDCTL_DSP_GETTRIGGER:
-               val = 0;
-               if (file->f_mode & FMODE_READ && as->usbin.flags & FLG_RUNNING) 
-                       val |= PCM_ENABLE_INPUT;
-               if (file->f_mode & FMODE_WRITE && as->usbout.flags & FLG_RUNNING) 
-                       val |= PCM_ENABLE_OUTPUT;
-               return put_user(val, user_arg);
-
-       case SNDCTL_DSP_SETTRIGGER:
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               if (file->f_mode & FMODE_READ) {
-                       if (val & PCM_ENABLE_INPUT) {
-                               if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
-                                       return ret;
-                               if (usbin_start(as))
-                                       return -ENODEV;
-                       } else
-                               usbin_stop(as);
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       if (val & PCM_ENABLE_OUTPUT) {
-                               if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
-                                       return ret;
-                               if (usbout_start(as))
-                                       return -ENODEV;
-                       } else
-                               usbout_stop(as);
-               }
-               return 0;
-
-       case SNDCTL_DSP_GETOSPACE:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
-                       return val;
-               spin_lock_irqsave(&as->lock, flags);
-               abinfo.fragsize = as->usbout.dma.fragsize;
-               abinfo.bytes = as->usbout.dma.dmasize - as->usbout.dma.count;
-               abinfo.fragstotal = as->usbout.dma.numfrag;
-               abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift;      
-               spin_unlock_irqrestore(&as->lock, flags);
-               return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_GETISPACE:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
-                       return val;
-               spin_lock_irqsave(&as->lock, flags);
-               abinfo.fragsize = as->usbin.dma.fragsize;
-               abinfo.bytes = as->usbin.dma.count;
-               abinfo.fragstotal = as->usbin.dma.numfrag;
-               abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift;      
-               spin_unlock_irqrestore(&as->lock, flags);
-               return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-               
-       case SNDCTL_DSP_NONBLOCK:
-               file->f_flags |= O_NONBLOCK;
-               return 0;
-
-       case SNDCTL_DSP_GETODELAY:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               spin_lock_irqsave(&as->lock, flags);
-               val = as->usbout.dma.count;
-               spin_unlock_irqrestore(&as->lock, flags);
-               return put_user(val, user_arg);
-
-       case SNDCTL_DSP_GETIPTR:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               spin_lock_irqsave(&as->lock, flags);
-               cinfo.bytes = as->usbin.dma.total_bytes;
-               cinfo.blocks = as->usbin.dma.count >> as->usbin.dma.fragshift;
-               cinfo.ptr = as->usbin.dma.wrptr;
-               if (as->usbin.dma.mapped)
-                       as->usbin.dma.count &= as->usbin.dma.fragsize-1;
-               spin_unlock_irqrestore(&as->lock, flags);
-               if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
-                       return -EFAULT;
-               return 0;
-
-       case SNDCTL_DSP_GETOPTR:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               spin_lock_irqsave(&as->lock, flags);
-               cinfo.bytes = as->usbout.dma.total_bytes;
-               cinfo.blocks = as->usbout.dma.count >> as->usbout.dma.fragshift;
-               cinfo.ptr = as->usbout.dma.rdptr;
-               if (as->usbout.dma.mapped)
-                       as->usbout.dma.count &= as->usbout.dma.fragsize-1;
-               spin_unlock_irqrestore(&as->lock, flags);
-               if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
-                       return -EFAULT;
-               return 0;
-
-       case SNDCTL_DSP_GETBLKSIZE:
-               if (file->f_mode & FMODE_WRITE) {
-                       if ((val = prog_dmabuf_out(as)))
-                               return val;
-                       return put_user(as->usbout.dma.fragsize, user_arg);
-               }
-               if ((val = prog_dmabuf_in(as)))
-                       return val;
-               return put_user(as->usbin.dma.fragsize, user_arg);
-
-       case SNDCTL_DSP_SETFRAGMENT:
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               if (file->f_mode & FMODE_READ) {
-                       as->usbin.dma.ossfragshift = val & 0xffff;
-                       as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff;
-                       if (as->usbin.dma.ossfragshift < 4)
-                               as->usbin.dma.ossfragshift = 4;
-                       if (as->usbin.dma.ossfragshift > 15)
-                               as->usbin.dma.ossfragshift = 15;
-                       if (as->usbin.dma.ossmaxfrags < 4)
-                               as->usbin.dma.ossmaxfrags = 4;
-               }
-               if (file->f_mode & FMODE_WRITE) {
-                       as->usbout.dma.ossfragshift = val & 0xffff;
-                       as->usbout.dma.ossmaxfrags = (val >> 16) & 0xffff;
-                       if (as->usbout.dma.ossfragshift < 4)
-                               as->usbout.dma.ossfragshift = 4;
-                       if (as->usbout.dma.ossfragshift > 15)
-                               as->usbout.dma.ossfragshift = 15;
-                       if (as->usbout.dma.ossmaxfrags < 4)
-                               as->usbout.dma.ossmaxfrags = 4;
-               }
-               return 0;
-
-       case SNDCTL_DSP_SUBDIVIDE:
-               if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) ||
-                   (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision))
-                       return -EINVAL;
-               if (get_user(val, user_arg))
-                       return -EFAULT;
-               if (val != 1 && val != 2 && val != 4)
-                       return -EINVAL;
-               if (file->f_mode & FMODE_READ)
-                       as->usbin.dma.subdivision = val;
-               if (file->f_mode & FMODE_WRITE)
-                       as->usbout.dma.subdivision = val;
-               return 0;
-
-       case SOUND_PCM_READ_RATE:
-               return put_user((file->f_mode & FMODE_READ) ? 
-                               as->usbin.dma.srate : as->usbout.dma.srate,
-                               user_arg);
-
-       case SOUND_PCM_READ_CHANNELS:
-               val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-               return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg);
-
-       case SOUND_PCM_READ_BITS:
-               val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-               return put_user(AFMT_IS16BIT(val2) ? 16 : 8, user_arg);
-
-       case SOUND_PCM_WRITE_FILTER:
-       case SNDCTL_DSP_SETSYNCRO:
-       case SOUND_PCM_READ_FILTER:
-               return -EINVAL;
-       }
-       dprintk((KERN_DEBUG "usbaudio: usb_audio_ioctl - no command found\n"));
-       return -ENOIOCTLCMD;
-}
-
-static int usb_audio_open(struct inode *inode, struct file *file)
-{
-       unsigned int minor = iminor(inode);
-       DECLARE_WAITQUEUE(wait, current);
-       struct usb_audiodev *as;
-       struct usb_audio_state *s;
-
-       for (;;) {
-               down(&open_sem);
-               list_for_each_entry(s, &audiodevs, audiodev) {
-                       list_for_each_entry(as, &s->audiolist, list) {
-                               if (!((as->dev_audio ^ minor) & ~0xf))
-                                       goto device_found;
-                       }
-               }
-               up(&open_sem);
-               return -ENODEV;
-
-       device_found:
-               if (!s->usbdev) {
-                       up(&open_sem);
-                       return -EIO;
-               }
-               /* wait for device to become free */
-               if (!(as->open_mode & file->f_mode))
-                       break;
-               if (file->f_flags & O_NONBLOCK) {
-                       up(&open_sem);
-                       return -EBUSY;
-               }
-               __set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&open_wait, &wait);
-               up(&open_sem);
-               schedule();
-               __set_current_state(TASK_RUNNING);
-               remove_wait_queue(&open_wait, &wait);
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
-       }
-       if (file->f_mode & FMODE_READ)
-               as->usbin.dma.ossfragshift = as->usbin.dma.ossmaxfrags = as->usbin.dma.subdivision = 0;
-       if (file->f_mode & FMODE_WRITE)
-               as->usbout.dma.ossfragshift = as->usbout.dma.ossmaxfrags = as->usbout.dma.subdivision = 0;
-       if (set_format(as, file->f_mode, ((minor & 0xf) == SND_DEV_DSP16) ? AFMT_S16_LE : AFMT_U8 /* AFMT_ULAW */, 8000)) {
-               up(&open_sem);
-               return -EIO;
-       }
-       file->private_data = as;
-       as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-       s->count++;
-       up(&open_sem);
-       return nonseekable_open(inode, file);
-}
-
-static int usb_audio_release(struct inode *inode, struct file *file)
-{
-       struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-       struct usb_audio_state *s;
-       struct usb_device *dev;
-
-       lock_kernel();
-       s = as->state;
-       dev = s->usbdev;
-       if (file->f_mode & FMODE_WRITE)
-               drain_out(as, file->f_flags & O_NONBLOCK);
-       down(&open_sem);
-       if (file->f_mode & FMODE_WRITE) {
-               usbout_stop(as);
-               if (dev && as->usbout.interface >= 0)
-                       usb_set_interface(dev, as->usbout.interface, 0);
-               dmabuf_release(&as->usbout.dma);
-               usbout_release(as);
-       }
-       if (file->f_mode & FMODE_READ) {
-               usbin_stop(as);
-               if (dev && as->usbin.interface >= 0)
-                       usb_set_interface(dev, as->usbin.interface, 0);
-               dmabuf_release(&as->usbin.dma);
-               usbin_release(as);
-       }
-       as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-       release(s);
-       wake_up(&open_wait);
-       unlock_kernel();
-       return 0;
-}
-
-static /*const*/ struct file_operations usb_audio_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .read =         usb_audio_read,
-       .write =        usb_audio_write,
-       .poll =         usb_audio_poll,
-       .ioctl =        usb_audio_ioctl,
-       .mmap =         usb_audio_mmap,
-       .open =         usb_audio_open,
-       .release =      usb_audio_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int usb_audio_probe(struct usb_interface *iface,
-                          const struct usb_device_id *id);
-static void usb_audio_disconnect(struct usb_interface *iface);
-
-static struct usb_device_id usb_audio_ids [] = {
-    { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
-      .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = 1},
-    { }                                                /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_audio_ids);
-
-static struct usb_driver usb_audio_driver = {
-       .name =         "audio",
-       .probe =        usb_audio_probe,
-       .disconnect =   usb_audio_disconnect,
-       .id_table =     usb_audio_ids,
-};
-
-static void *find_descriptor(void *descstart, unsigned int desclen, void *after, 
-                            u8 dtype, int iface, int altsetting)
-{
-       u8 *p, *end, *next;
-       int ifc = -1, as = -1;
-
-       p = descstart;
-       end = p + desclen;
-       for (; p < end;) {
-               if (p[0] < 2)
-                       return NULL;
-               next = p + p[0];
-               if (next > end)
-                       return NULL;
-               if (p[1] == USB_DT_INTERFACE) {
-                       /* minimum length of interface descriptor */
-                       if (p[0] < 9)
-                               return NULL;
-                       ifc = p[2];
-                       as = p[3];
-               }
-               if (p[1] == dtype && (!after || (void *)p > after) &&
-                   (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) {
-                       return p;
-               }
-               p = next;
-       }
-       return NULL;
-}
-
-static void *find_csinterface_descriptor(void *descstart, unsigned int desclen, void *after, u8 dsubtype, int iface, int altsetting)
-{
-       unsigned char *p;
-
-       p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, altsetting);
-       while (p) {
-               if (p[0] >= 3 && p[2] == dsubtype)
-                       return p;
-               p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, altsetting);
-       }
-       return NULL;
-}
-
-static void *find_audiocontrol_unit(void *descstart, unsigned int desclen, void *after, u8 unit, int iface)
-{
-       unsigned char *p;
-
-       p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, -1);
-       while (p) {
-               if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
-                       return p;
-               p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, -1);
-       }
-       return NULL;
-}
-
-static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, int asifin, int asifout)
-{
-       struct usb_device *dev = s->usbdev;
-       struct usb_audiodev *as;
-       struct usb_host_interface *alts;
-       struct usb_interface *iface;
-       struct audioformat *fp;
-       unsigned char *fmt, *csep;
-       unsigned int i, j, k, format, idx;
-
-       if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL)))
-               return;
-       memset(as, 0, sizeof(struct usb_audiodev));
-       init_waitqueue_head(&as->usbin.dma.wait);
-       init_waitqueue_head(&as->usbout.dma.wait);
-       spin_lock_init(&as->lock);
-       as->usbin.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-       as->usbin.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-       as->usbin.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-       as->usbin.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-       as->usbout.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-       as->usbout.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-       as->usbout.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-       as->usbout.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-       if ((!as->usbin.durb[0].urb) ||
-           (!as->usbin.durb[1].urb) ||
-           (!as->usbin.surb[0].urb) ||
-           (!as->usbin.surb[1].urb) ||
-           (!as->usbout.durb[0].urb) ||
-           (!as->usbout.durb[1].urb) ||
-           (!as->usbout.surb[0].urb) ||
-           (!as->usbout.surb[1].urb)) {
-               usb_free_urb(as->usbin.durb[0].urb);
-               usb_free_urb(as->usbin.durb[1].urb);
-               usb_free_urb(as->usbin.surb[0].urb);
-               usb_free_urb(as->usbin.surb[1].urb);
-               usb_free_urb(as->usbout.durb[0].urb);
-               usb_free_urb(as->usbout.durb[1].urb);
-               usb_free_urb(as->usbout.surb[0].urb);
-               usb_free_urb(as->usbout.surb[1].urb);
-               kfree(as);
-               return;
-       }
-       as->state = s;
-       as->usbin.interface = asifin;
-       as->usbout.interface = asifout;
-       /* search for input formats */
-       if (asifin >= 0) {
-               as->usbin.flags = FLG_CONNECTED;
-               iface = usb_ifnum_to_if(dev, asifin);
-               for (idx = 0; idx < iface->num_altsetting; idx++) {
-                       alts = &iface->altsetting[idx];
-                       i = alts->desc.bAlternateSetting;
-                       if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2)
-                               continue;
-                       if (alts->desc.bNumEndpoints < 1) {
-                               if (i != 0) {  /* altsetting 0 has no endpoints (Section B.3.4.1) */
-                                       printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
-                                              dev->devnum, asifin, i);
-                               }
-                               continue;
-                       }
-                       if ((alts->endpoint[0].desc.bmAttributes & 0x03) != 0x01 ||
-                           !(alts->endpoint[0].desc.bEndpointAddress & 0x80)) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous in\n", 
-                                      dev->devnum, asifin, i);
-                               continue;
-                       }
-                       fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifin, i);
-                       if (!fmt) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-                                      dev->devnum, asifin, i);
-                               continue;
-                       }
-                       if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", 
-                                      dev->devnum, asifin, i);
-                               continue;
-                       }
-                       format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
-                       fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
-                       if (!fmt) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-                                      dev->devnum, asifin, i);
-                               continue;
-                       }
-                       if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
-                                      dev->devnum, asifin, i);
-                               continue;
-                       }
-                       if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
-                                      dev->devnum, asifin, i, fmt[4], fmt[5]);
-                               continue;
-                       }
-                       csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifin, i);
-                       if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", 
-                                      dev->devnum, asifin, i);
-                               continue;
-                       }
-                       if (as->numfmtin >= MAXFORMATS)
-                               continue;
-                       fp = &as->fmtin[as->numfmtin++];
-                       if (fmt[5] == 2)
-                               format &= (AFMT_U16_LE | AFMT_S16_LE);
-                       else
-                               format &= (AFMT_U8 | AFMT_S8);
-                       if (fmt[4] == 2)
-                               format |= AFMT_STEREO;
-                       fp->format = format;
-                       fp->altsetting = i;
-                       fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
-                       printk(KERN_INFO "usbaudio: valid input sample rate %u\n", fp->sratelo);
-                       for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
-                               k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
-                               printk(KERN_INFO "usbaudio: valid input sample rate %u\n", k);
-                               if (k > fp->sratehi)
-                                       fp->sratehi = k;
-                               if (k < fp->sratelo)
-                                       fp->sratelo = k;
-                       }
-                       fp->attributes = csep[3];
-                       printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", 
-                              dev->devnum, asifin, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes);
-               }
-       }
-       /* search for output formats */
-       if (asifout >= 0) {
-               as->usbout.flags = FLG_CONNECTED;
-               iface = usb_ifnum_to_if(dev, asifout);
-               for (idx = 0; idx < iface->num_altsetting; idx++) {
-                       alts = &iface->altsetting[idx];
-                       i = alts->desc.bAlternateSetting;
-                       if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2)
-                               continue;
-                       if (alts->desc.bNumEndpoints < 1) {
-                               /* altsetting 0 should never have iso EPs */
-                               if (i != 0)
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
-                                      dev->devnum, asifout, i);
-                               continue;
-                       }
-                       if ((alts->endpoint[0].desc.bmAttributes & 0x03) != 0x01 ||
-                           (alts->endpoint[0].desc.bEndpointAddress & 0x80)) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous out\n", 
-                                      dev->devnum, asifout, i);
-                               continue;
-                       }
-                       /* See USB audio formats manual, section 2 */
-                       fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifout, i);
-                       if (!fmt) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-                                      dev->devnum, asifout, i);
-                               continue;
-                       }
-                       if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", 
-                                      dev->devnum, asifout, i);
-                               continue;
-                       }
-                       format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
-                       /* Dallas DS4201 workaround */
-                       if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && 
-                           le16_to_cpu(dev->descriptor.idProduct) == 0x4201)
-                               format = (AFMT_S16_LE | AFMT_S8);
-                       fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifout, i);
-                       if (!fmt) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-                                      dev->devnum, asifout, i);
-                               continue;
-                       }
-                       if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
-                                      dev->devnum, asifout, i);
-                               continue;
-                       }
-                       if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
-                                      dev->devnum, asifout, i, fmt[4], fmt[5]);
-                               continue;
-                       }
-                       csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifout, i);
-                       if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
-                               printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", 
-                                      dev->devnum, asifout, i);
-                               continue;
-                       }
-                       if (as->numfmtout >= MAXFORMATS)
-                               continue;
-                       fp = &as->fmtout[as->numfmtout++];
-                       if (fmt[5] == 2)
-                               format &= (AFMT_U16_LE | AFMT_S16_LE);
-                       else
-                               format &= (AFMT_U8 | AFMT_S8);
-                       if (fmt[4] == 2)
-                               format |= AFMT_STEREO;
-                       fp->format = format;
-                       fp->altsetting = i;
-                       fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
-                       printk(KERN_INFO "usbaudio: valid output sample rate %u\n", fp->sratelo);
-                       for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
-                               k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
-                               printk(KERN_INFO "usbaudio: valid output sample rate %u\n", k);
-                               if (k > fp->sratehi)
-                                       fp->sratehi = k;
-                               if (k < fp->sratelo)
-                                       fp->sratelo = k;
-                       }
-                       fp->attributes = csep[3];
-                       printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", 
-                              dev->devnum, asifout, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes);
-               }
-       }
-       if (as->numfmtin == 0 && as->numfmtout == 0) {
-               usb_free_urb(as->usbin.durb[0].urb);
-               usb_free_urb(as->usbin.durb[1].urb);
-               usb_free_urb(as->usbin.surb[0].urb);
-               usb_free_urb(as->usbin.surb[1].urb);
-               usb_free_urb(as->usbout.durb[0].urb);
-               usb_free_urb(as->usbout.durb[1].urb);
-               usb_free_urb(as->usbout.surb[0].urb);
-               usb_free_urb(as->usbout.surb[1].urb);
-               kfree(as);
-               return;
-       }
-       if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
-               printk(KERN_ERR "usbaudio: cannot register dsp\n");
-               usb_free_urb(as->usbin.durb[0].urb);
-               usb_free_urb(as->usbin.durb[1].urb);
-               usb_free_urb(as->usbin.surb[0].urb);
-               usb_free_urb(as->usbin.surb[1].urb);
-               usb_free_urb(as->usbout.durb[0].urb);
-               usb_free_urb(as->usbout.durb[1].urb);
-               usb_free_urb(as->usbout.surb[0].urb);
-               usb_free_urb(as->usbout.surb[1].urb);
-               kfree(as);
-               return;
-       }
-       printk(KERN_INFO "usbaudio: registered dsp 14,%d\n", as->dev_audio);
-       /* everything successful */
-       list_add_tail(&as->list, &s->audiolist);
-}
-
-struct consmixstate {
-       struct usb_audio_state *s;
-       unsigned char *buffer;
-       unsigned int buflen;
-       unsigned int ctrlif;
-       struct mixerchannel mixch[SOUND_MIXER_NRDEVICES];
-       unsigned int nrmixch;
-       unsigned int mixchmask;
-       unsigned long unitbitmap[32/sizeof(unsigned long)];
-       /* return values */
-       unsigned int nrchannels;
-       unsigned int termtype;
-       unsigned int chconfig;
-};
-
-static struct mixerchannel *getmixchannel(struct consmixstate *state, unsigned int nr)
-{
-       struct mixerchannel *c;
-
-       if (nr >= SOUND_MIXER_NRDEVICES) {
-               printk(KERN_ERR "usbaudio: invalid OSS mixer channel %u\n", nr);
-               return NULL;
-       }
-       if (!(state->mixchmask & (1 << nr))) {
-               printk(KERN_WARNING "usbaudio: OSS mixer channel %u already in use\n", nr);
-               return NULL;
-       }
-       c = &state->mixch[state->nrmixch++];
-       c->osschannel = nr;
-       state->mixchmask &= ~(1 << nr);
-       return c;
-}
-
-static unsigned int getvolchannel(struct consmixstate *state)
-{
-       unsigned int u;
-
-       if ((state->termtype & 0xff00) == 0x0000 && (state->mixchmask & SOUND_MASK_VOLUME))
-               return SOUND_MIXER_VOLUME;
-       if ((state->termtype & 0xff00) == 0x0100) {
-               if (state->mixchmask & SOUND_MASK_PCM)
-                       return SOUND_MIXER_PCM;
-               if (state->mixchmask & SOUND_MASK_ALTPCM)
-                       return SOUND_MIXER_ALTPCM;
-       }
-       if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC))
-               return SOUND_MIXER_MIC;
-       if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
-               return SOUND_MIXER_SPEAKER;
-       if ((state->termtype & 0xff00) == 0x0500) {
-               if (state->mixchmask & SOUND_MASK_PHONEIN)
-                       return SOUND_MIXER_PHONEIN;
-               if (state->mixchmask & SOUND_MASK_PHONEOUT)
-                       return SOUND_MIXER_PHONEOUT;
-       }
-       if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO))
-               return SOUND_MIXER_RADIO;
-       if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO))
-               return SOUND_MIXER_VIDEO;
-       u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 |
-                                   SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3));
-       return u-1;
-}
-
-static void prepmixch(struct consmixstate *state)
-{
-       struct usb_device *dev = state->s->usbdev;
-       struct mixerchannel *ch;
-       unsigned char *buf;
-       __s16 v1;
-       unsigned int v2, v3;
-
-       if (!state->nrmixch || state->nrmixch > SOUND_MIXER_NRDEVICES)
-               return;
-       buf = kmalloc(sizeof(*buf) * 2, GFP_KERNEL);
-       if (!buf) {
-               printk(KERN_ERR "prepmixch: out of memory\n") ;
-               return;
-       }
-
-       ch = &state->mixch[state->nrmixch-1];
-       switch (ch->selector) {
-       case 0:  /* mixer unit request */
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-                       goto err;
-               ch->minval = buf[0] | (buf[1] << 8);
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-                       goto err;
-               ch->maxval = buf[0] | (buf[1] << 8);
-               v2 = ch->maxval - ch->minval;
-               if (!v2)
-                       v2 = 1;
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-                       goto err;
-               v1 = buf[0] | (buf[1] << 8);
-               v3 = v1 - ch->minval;
-               v3 = 100 * v3 / v2;
-               if (v3 > 100)
-                       v3 = 100;
-               ch->value = v3;
-               if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-                       if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                           ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-                                           state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-                       goto err;
-                       v1 = buf[0] | (buf[1] << 8);
-                       v3 = v1 - ch->minval;
-                       v3 = 100 * v3 / v2;
-                       if (v3 > 100)
-                               v3 = 100;
-               }
-               ch->value |= v3 << 8;
-               break;
-
-               /* various feature unit controls */
-       case VOLUME_CONTROL:
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-                       goto err;
-               ch->minval = buf[0] | (buf[1] << 8);
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-                       goto err;
-               ch->maxval = buf[0] | (buf[1] << 8);
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-                       goto err;
-               v1 = buf[0] | (buf[1] << 8);
-               v2 = ch->maxval - ch->minval;
-               v3 = v1 - ch->minval;
-               if (!v2)
-                       v2 = 1;
-               v3 = 100 * v3 / v2;
-               if (v3 > 100)
-                       v3 = 100;
-               ch->value = v3;
-               if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-                       if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                           (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-                               goto err;
-                       v1 = buf[0] | (buf[1] << 8);
-                       v3 = v1 - ch->minval;
-                       v3 = 100 * v3 / v2;
-                       if (v3 > 100)
-                               v3 = 100;
-               }
-               ch->value |= v3 << 8;
-               break;
-               
-       case BASS_CONTROL:
-       case MID_CONTROL:
-       case TREBLE_CONTROL:
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-                       goto err;
-               ch->minval = buf[0] << 8;
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-                       goto err;
-               ch->maxval = buf[0] << 8;
-               if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                   (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-                       goto err;
-               v1 = buf[0] << 8;
-               v2 = ch->maxval - ch->minval;
-               v3 = v1 - ch->minval;
-               if (!v2)
-                       v2 = 1;
-               v3 = 100 * v3 / v2;
-               if (v3 > 100)
-                       v3 = 100;
-               ch->value = v3;
-               if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-                       if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-                                           (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-                               goto err;
-                       v1 = buf[0] << 8;
-                       v3 = v1 - ch->minval;
-                       v3 = 100 * v3 / v2;
-                       if (v3 > 100)
-                               v3 = 100;
-               }
-               ch->value |= v3 << 8;
-               break;
-               
-       default:
-               goto err;
-       }
-
- freebuf:
-       kfree(buf);
-       return;
- err:
-       printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
-              dev->devnum, state->ctrlif, ch->unitid, ch->chnum, ch->selector);
-       if (state->nrmixch)
-               state->nrmixch--;
-       goto freebuf;
-}
-
-
-static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid);
-
-static inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch)
-{
-       unsigned int idx;
-
-       idx = inidx*numoch;
-       if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
-               return 0;
-       if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-               return 1;
-       idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT);
-       if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
-               return 0;
-       return 1;
-}
-
-static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer)
-{
-       unsigned int nroutch = mixer[5+mixer[4]];
-       unsigned int chidx[SOUND_MIXER_NRDEVICES+1];
-       unsigned int termt[SOUND_MIXER_NRDEVICES];
-       unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0;
-       unsigned char *bmap = &mixer[9+mixer[4]];
-       unsigned int bmapsize;
-       struct mixerchannel *ch;
-       unsigned int i;
-
-       if (!mixer[4]) {
-               printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor\n", mixer[3]);
-               return;
-       }
-       if (mixer[4] > SOUND_MIXER_NRDEVICES) {
-               printk(KERN_ERR "usbaudio: mixer unit %u: too many input pins\n", mixer[3]);
-               return;
-       }
-       chidx[0] = 0;
-       for (i = 0; i < mixer[4]; i++) {
-               usb_audio_recurseunit(state, mixer[5+i]);
-               chidx[i+1] = chidx[i] + state->nrchannels;
-               termt[i] = state->termtype;
-       }
-       state->termtype = 0;
-       state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8);
-       bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3;
-       bmap += bmapsize - 1;
-       if (mixer[0] < 10+mixer[4]+bmapsize) {
-               printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]);
-               return;
-       }
-       for (i = 0; i < mixer[4]; i++) {
-               state->termtype = termt[i];
-               if (chidx[i+1]-chidx[i] >= 2) {
-                       flg |= MIXFLG_STEREOIN;
-                       if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
-                               ch = getmixchannel(state, getvolchannel(state));
-                               if (ch) {
-                                       ch->unitid = mixer[3];
-                                       ch->selector = 0;
-                                       ch->chnum = chidx[i]+1;
-                                       ch->flags = flg;
-                                       prepmixch(state);
-                               }
-                               continue;
-                       }
-               }
-               flg &= ~MIXFLG_STEREOIN;
-               if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
-                       ch = getmixchannel(state, getvolchannel(state));
-                       if (ch) {
-                               ch->unitid = mixer[3];
-                               ch->selector = 0;
-                               ch->chnum = chidx[i]+1;
-                               ch->flags = flg;
-                               prepmixch(state);
-                       }
-               }
-       }       
-       state->termtype = 0;
-}
-
-static struct mixerchannel *slctsrc_findunit(struct consmixstate *state, __u8 unitid)
-{
-       unsigned int i;
-       
-       for (i = 0; i < state->nrmixch; i++)
-               if (state->mixch[i].unitid == unitid)
-                       return &state->mixch[i];
-       return NULL;
-}
-
-static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector)
-{
-       unsigned int chnum, i, mixch;
-       struct mixerchannel *mch;
-
-       if (!selector[4]) {
-               printk(KERN_ERR "usbaudio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]);
-               return;
-       }
-       mixch = state->nrmixch;
-       usb_audio_recurseunit(state, selector[5]);
-       if (state->nrmixch != mixch) {
-               mch = &state->mixch[state->nrmixch-1];
-               mch->slctunitid = selector[3] | (1 << 8);
-       } else if ((mch = slctsrc_findunit(state, selector[5]))) {
-               mch->slctunitid = selector[3] | (1 << 8);
-       } else {
-               printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]);
-       }
-       chnum = state->nrchannels;
-       for (i = 1; i < selector[4]; i++) {
-               mixch = state->nrmixch;
-               usb_audio_recurseunit(state, selector[5+i]);
-               if (chnum != state->nrchannels) {
-                       printk(KERN_ERR "usbaudio: selector unit %u: input pins with varying channel numbers\n", selector[3]);
-                       state->termtype = 0;
-                       state->chconfig = 0;
-                       state->nrchannels = 0;
-                       return;
-               }
-               if (state->nrmixch != mixch) {
-                       mch = &state->mixch[state->nrmixch-1];
-                       mch->slctunitid = selector[3] | ((i + 1) << 8);
-               } else if ((mch = slctsrc_findunit(state, selector[5+i]))) {
-                       mch->slctunitid = selector[3] | ((i + 1) << 8);
-               } else {
-                       printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1);
-               }
-       }
-       state->termtype = 0;
-       state->chconfig = 0;
-}
-
-/* in the future we might try to handle 3D etc. effect units */
-
-static void usb_audio_processingunit(struct consmixstate *state, unsigned char *proc)
-{
-       unsigned int i;
-
-       for (i = 0; i < proc[6]; i++)
-               usb_audio_recurseunit(state, proc[7+i]);
-       state->nrchannels = proc[7+proc[6]];
-       state->termtype = 0;
-       state->chconfig = proc[8+proc[6]] | (proc[9+proc[6]] << 8);
-}
-
-
-/* See Audio Class Spec, section 4.3.2.5 */
-static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr)
-{
-       struct mixerchannel *ch;
-       unsigned short chftr, mchftr;
-#if 0
-       struct usb_device *dev = state->s->usbdev;
-       unsigned char data[1];
-#endif
-       unsigned char nr_logical_channels, i;
-
-       usb_audio_recurseunit(state, ftr[4]);
-
-       if (ftr[5] == 0 ) {
-               printk(KERN_ERR "usbaudio: wrong controls size in feature unit %u\n",ftr[3]);
-               return;
-       }
-
-       if (state->nrchannels == 0) {
-               printk(KERN_ERR "usbaudio: feature unit %u source has no channels\n", ftr[3]);
-               return;
-       }
-       if (state->nrchannels > 2)
-               printk(KERN_WARNING "usbaudio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]);
-
-       nr_logical_channels=(ftr[0]-7)/ftr[5]-1;
-
-       if (nr_logical_channels != state->nrchannels) {
-               printk(KERN_WARNING "usbaudio: warning: found %d of %d logical channels.\n", state->nrchannels,nr_logical_channels);
-
-               if (state->nrchannels == 1 && nr_logical_channels==0) {
-                       printk(KERN_INFO "usbaudio: assuming the channel found is the master channel (got a Philips camera?). Should be fine.\n");
-               } else if (state->nrchannels == 1 && nr_logical_channels==2) {
-                       printk(KERN_INFO "usbaudio: assuming that a stereo channel connected directly to a mixer is missing in search (got Labtec headset?). Should be fine.\n");
-                       state->nrchannels=nr_logical_channels;
-               } else {
-                       printk(KERN_WARNING "usbaudio: no idea what's going on..., contact linux-usb-devel@lists.sourceforge.net\n");
-               }
-       }
-
-       /* There is always a master channel */
-       mchftr = ftr[6];
-       /* Binary AND over logical channels if they exist */
-       if (nr_logical_channels) {
-               chftr = ftr[6+ftr[5]];
-               for (i = 2; i <= nr_logical_channels; i++)
-                       chftr &= ftr[6+i*ftr[5]];
-       } else {
-               chftr = 0;
-       }
-
-       /* volume control */
-       if (chftr & 2) {
-               ch = getmixchannel(state, getvolchannel(state));
-               if (ch) {
-                       ch->unitid = ftr[3];
-                       ch->selector = VOLUME_CONTROL;
-                       ch->chnum = 1;
-                       ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-                       prepmixch(state);
-               }
-       } else if (mchftr & 2) {
-               ch = getmixchannel(state, getvolchannel(state));
-               if (ch) {
-                       ch->unitid = ftr[3];
-                       ch->selector = VOLUME_CONTROL;
-                       ch->chnum = 0;
-                       ch->flags = 0;
-                       prepmixch(state);
-               }
-       }
-       /* bass control */
-       if (chftr & 4) {
-               ch = getmixchannel(state, SOUND_MIXER_BASS);
-               if (ch) {
-                       ch->unitid = ftr[3];
-                       ch->selector = BASS_CONTROL;
-                       ch->chnum = 1;
-                       ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-                       prepmixch(state);
-               }
-       } else if (mchftr & 4) {
-               ch = getmixchannel(state, SOUND_MIXER_BASS);
-               if (ch) {
-                       ch->unitid = ftr[3];
-                       ch->selector = BASS_CONTROL;
-                       ch->chnum = 0;
-                       ch->flags = 0;
-                       prepmixch(state);
-               }
-       }
-       /* treble control */
-       if (chftr & 16) {
-               ch = getmixchannel(state, SOUND_MIXER_TREBLE);
-               if (ch) {
-                       ch->unitid = ftr[3];
-                       ch->selector = TREBLE_CONTROL;
-                       ch->chnum = 1;
-                       ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-                       prepmixch(state);
-               }
-       } else if (mchftr & 16) {
-               ch = getmixchannel(state, SOUND_MIXER_TREBLE);
-               if (ch) {
-                       ch->unitid = ftr[3];
-                       ch->selector = TREBLE_CONTROL;
-                       ch->chnum = 0;
-                       ch->flags = 0;
-                       prepmixch(state);
-               }
-       }
-#if 0
-       /* if there are mute controls, unmute them */
-       /* does not seem to be necessary, and the Dallas chip does not seem to support the "all" channel (255) */
-       if ((chftr & 1) || (mchftr & 1)) {
-               printk(KERN_DEBUG "usbaudio: unmuting feature unit %u interface %u\n", ftr[3], state->ctrlif);
-               data[0] = 0;
-               if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                   (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, 1000) < 0)
-                       printk(KERN_WARNING "usbaudio: failure to unmute feature unit %u interface %u\n", ftr[3], state->ctrlif);
-       }
-#endif
-}
-
-static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid)
-{
-       unsigned char *p1;
-       unsigned int i, j;
-
-       if (test_and_set_bit(unitid, state->unitbitmap)) {
-               printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid);
-               return;
-       }
-       p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif);
-       if (!p1) {
-               printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);
-               return;
-       }
-       state->nrchannels = 0;
-       state->termtype = 0;
-       state->chconfig = 0;
-       switch (p1[2]) {
-       case INPUT_TERMINAL:
-               if (p1[0] < 12) {
-                       printk(KERN_ERR "usbaudio: unit %u: invalid INPUT_TERMINAL descriptor\n", unitid);
-                       return;
-               }
-               state->nrchannels = p1[7];
-               state->termtype = p1[4] | (p1[5] << 8);
-               state->chconfig = p1[8] | (p1[9] << 8);
-               return;
-
-       case MIXER_UNIT:
-               if (p1[0] < 10 || p1[0] < 10+p1[4]) {
-                       printk(KERN_ERR "usbaudio: unit %u: invalid MIXER_UNIT descriptor\n", unitid);
-                       return;
-               }
-               usb_audio_mixerunit(state, p1);
-               return;
-
-       case SELECTOR_UNIT:
-               if (p1[0] < 6 || p1[0] < 6+p1[4]) {
-                       printk(KERN_ERR "usbaudio: unit %u: invalid SELECTOR_UNIT descriptor\n", unitid);
-                       return;
-               }
-               usb_audio_selectorunit(state, p1);
-               return;
-
-       case FEATURE_UNIT: /* See USB Audio Class Spec 4.3.2.5 */
-               if (p1[0] < 7 || p1[0] < 7+p1[5]) {
-                       printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
-                       return;
-               }
-               usb_audio_featureunit(state, p1);
-               return;         
-
-       case PROCESSING_UNIT:
-               if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
-                       printk(KERN_ERR "usbaudio: unit %u: invalid PROCESSING_UNIT descriptor\n", unitid);
-                       return;
-               }
-               usb_audio_processingunit(state, p1);
-               return;         
-
-       case EXTENSION_UNIT:
-               if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
-                       printk(KERN_ERR "usbaudio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid);
-                       return;
-               }
-               for (j = i = 0; i < p1[6]; i++) {
-                       usb_audio_recurseunit(state, p1[7+i]);
-                       if (!i)
-                               j = state->termtype;
-                       else if (j != state->termtype)
-                               j = 0;
-               }
-               state->nrchannels = p1[7+p1[6]];
-               state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8);
-               state->termtype = j;
-               return;
-
-       default:
-               printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
-               return;
-       }
-}
-
-static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif, unsigned char *oterm)
-{
-       struct usb_mixerdev *ms;
-       struct consmixstate state;
-
-       memset(&state, 0, sizeof(state));
-       state.s = s;
-       state.nrmixch = 0;
-       state.mixchmask = ~0;
-       state.buffer = buffer;
-       state.buflen = buflen;
-       state.ctrlif = ctrlif;
-       set_bit(oterm[3], state.unitbitmap);  /* mark terminal ID as visited */
-       printk(KERN_DEBUG "usbaudio: constructing mixer for Terminal %u type 0x%04x\n",
-              oterm[3], oterm[4] | (oterm[5] << 8));
-       usb_audio_recurseunit(&state, oterm[7]);
-       if (!state.nrmixch) {
-               printk(KERN_INFO "usbaudio: no mixer controls found for Terminal %u\n", oterm[3]);
-               return;
-       }
-       if (!(ms = kmalloc(sizeof(struct usb_mixerdev)+state.nrmixch*sizeof(struct mixerchannel), GFP_KERNEL)))
-               return;
-       memset(ms, 0, sizeof(struct usb_mixerdev));
-       memcpy(&ms->ch, &state.mixch, state.nrmixch*sizeof(struct mixerchannel));
-       ms->state = s;
-       ms->iface = ctrlif;
-       ms->numch = state.nrmixch;
-       if ((ms->dev_mixer = register_sound_mixer(&usb_mixer_fops, -1)) < 0) {
-               printk(KERN_ERR "usbaudio: cannot register mixer\n");
-               kfree(ms);
-               return;
-       }
-       printk(KERN_INFO "usbaudio: registered mixer 14,%d\n", ms->dev_mixer);
-       list_add_tail(&ms->list, &s->mixerlist);
-}
-
-/* arbitrary limit, we won't check more interfaces than this */
-#define USB_MAXINTERFACES      32
-
-static struct usb_audio_state *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
-{
-       struct usb_audio_state *s;
-       struct usb_interface *iface;
-       struct usb_host_interface *alt;
-       unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
-       unsigned char *p1;
-       unsigned int i, j, k, numifin = 0, numifout = 0;
-       
-       if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
-               return NULL;
-       memset(s, 0, sizeof(struct usb_audio_state));
-       INIT_LIST_HEAD(&s->audiolist);
-       INIT_LIST_HEAD(&s->mixerlist);
-       s->usbdev = dev;
-       s->count = 1;
-
-       /* find audiocontrol interface */
-       if (!(p1 = find_csinterface_descriptor(buffer, buflen, NULL, HEADER, ctrlif, -1))) {
-               printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u no HEADER found\n",
-                      dev->devnum, ctrlif);
-               goto ret;
-       }
-       if (p1[0] < 8 + p1[7]) {
-               printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u HEADER error\n",
-                      dev->devnum, ctrlif);
-               goto ret;
-       }
-       if (!p1[7])
-               printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has no AudioStreaming and MidiStreaming interfaces\n",
-                      dev->devnum, ctrlif);
-       for (i = 0; i < p1[7]; i++) {
-               j = p1[8+i];
-               iface = usb_ifnum_to_if(dev, j);
-               if (!iface) {
-                       printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u does not exist\n",
-                              dev->devnum, ctrlif, j);
-                       continue;
-               }
-               if (iface->num_altsetting == 1) {
-                       printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
-                       continue;
-               }
-               alt = usb_altnum_to_altsetting(iface, 0);
-               if (!alt) {
-                       printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 0\n",
-                              dev->devnum, ctrlif, j);
-                       continue;
-               }
-               if (alt->desc.bInterfaceClass != USB_CLASS_AUDIO) {
-                       printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n",
-                              dev->devnum, ctrlif, j);
-                       continue;
-               }
-               if (alt->desc.bInterfaceSubClass == 3) {
-                       printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n",
-                              dev->devnum, ctrlif, j);
-                       continue;
-               }
-               if (alt->desc.bInterfaceSubClass != 2) {
-                       printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n",
-                              dev->devnum, ctrlif, j);
-                       continue;
-               }
-               if (alt->desc.bNumEndpoints > 0) {
-                       /* Check all endpoints; should they all have a bandwidth of 0 ? */
-                       for (k = 0; k < alt->desc.bNumEndpoints; k++) {
-                               if (le16_to_cpu(alt->endpoint[k].desc.wMaxPacketSize) > 0) {
-                                       printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k);
-                                       break;
-                               }
-                       }
-                       if (k < alt->desc.bNumEndpoints)
-                               continue;
-               }
-
-               alt = usb_altnum_to_altsetting(iface, 1);
-               if (!alt) {
-                       printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 1\n",
-                              dev->devnum, ctrlif, j);
-                       continue;
-               }
-               if (alt->desc.bNumEndpoints < 1) {
-                       printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n",
-                              dev->devnum, ctrlif, j);
-                       continue;
-               }
-               /* note: this requires the data endpoint to be ep0 and the optional sync
-                  ep to be ep1, which seems to be the case */
-               if (alt->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) {
-                       if (numifin < USB_MAXINTERFACES) {
-                               ifin[numifin++] = j;
-                               usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
-                       }
-               } else {
-                       if (numifout < USB_MAXINTERFACES) {
-                               ifout[numifout++] = j;
-                               usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
-                       }
-               }
-       }
-       printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n",
-              dev->devnum, ctrlif, numifin, numifout);
-       for (i = 0; i < numifin && i < numifout; i++)
-               usb_audio_parsestreaming(s, buffer, buflen, ifin[i], ifout[i]);
-       for (j = i; j < numifin; j++)
-               usb_audio_parsestreaming(s, buffer, buflen, ifin[i], -1);
-       for (j = i; j < numifout; j++)
-               usb_audio_parsestreaming(s, buffer, buflen, -1, ifout[i]);
-       /* now walk through all OUTPUT_TERMINAL descriptors to search for mixers */
-       p1 = find_csinterface_descriptor(buffer, buflen, NULL, OUTPUT_TERMINAL, ctrlif, -1);
-       while (p1) {
-               if (p1[0] >= 9)
-                       usb_audio_constructmixer(s, buffer, buflen, ctrlif, p1);
-               p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
-       }
-
-ret:
-       if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
-               kfree(s);
-               return NULL;
-       }
-       /* everything successful */
-       down(&open_sem);
-       list_add_tail(&s->audiodev, &audiodevs);
-       up(&open_sem);
-       printk(KERN_DEBUG "usb_audio_parsecontrol: usb_audio_state at %p\n", s);
-       return s;
-}
-
-/* we only care for the currently active configuration */
-
-static int usb_audio_probe(struct usb_interface *intf,
-                          const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev (intf);
-       struct usb_audio_state *s;
-       unsigned char *buffer;
-       unsigned int buflen;
-
-#if 0
-       printk(KERN_DEBUG "usbaudio: Probing if %i: IC %x, ISC %x\n", ifnum,
-              config->interface[ifnum].altsetting[0].desc.bInterfaceClass,
-              config->interface[ifnum].altsetting[0].desc.bInterfaceSubClass);
-#endif
-
-       /*
-        * audiocontrol interface found
-        * find which configuration number is active
-        */
-       buffer = dev->rawdescriptors[dev->actconfig - dev->config];
-       buflen = le16_to_cpu(dev->actconfig->desc.wTotalLength);
-       s = usb_audio_parsecontrol(dev, buffer, buflen, intf->altsetting->desc.bInterfaceNumber);
-       if (s) {
-               usb_set_intfdata (intf, s);
-               return 0;
-       }
-       return -ENODEV;
-}
-
-
-/* a revoke facility would make things simpler */
-
-static void usb_audio_disconnect(struct usb_interface *intf)
-{
-       struct usb_audio_state *s = usb_get_intfdata (intf);
-       struct usb_audiodev *as;
-       struct usb_mixerdev *ms;
-
-       if (!s)
-               return;
-
-       /* we get called with -1 for every audiostreaming interface registered */
-       if (s == (struct usb_audio_state *)-1) {
-               dprintk((KERN_DEBUG "usbaudio: note, usb_audio_disconnect called with -1\n"));
-               return;
-       }
-       if (!s->usbdev) {
-               dprintk((KERN_DEBUG "usbaudio: error,  usb_audio_disconnect already called for %p!\n", s));
-               return;
-       }
-       down(&open_sem);
-       list_del_init(&s->audiodev);
-       s->usbdev = NULL;
-       usb_set_intfdata (intf, NULL);
-
-       /* deregister all audio and mixer devices, so no new processes can open this device */
-       list_for_each_entry(as, &s->audiolist, list) {
-               usbin_disc(as);
-               usbout_disc(as);
-               wake_up(&as->usbin.dma.wait);
-               wake_up(&as->usbout.dma.wait);
-               if (as->dev_audio >= 0) {
-                       unregister_sound_dsp(as->dev_audio);
-                       printk(KERN_INFO "usbaudio: unregister dsp 14,%d\n", as->dev_audio);
-               }
-               as->dev_audio = -1;
-       }
-       list_for_each_entry(ms, &s->mixerlist, list) {
-               if (ms->dev_mixer >= 0) {
-                       unregister_sound_mixer(ms->dev_mixer);
-                       printk(KERN_INFO "usbaudio: unregister mixer 14,%d\n", ms->dev_mixer);
-               }
-               ms->dev_mixer = -1;
-       }
-       release(s);
-       wake_up(&open_wait);
-}
-
-static int __init usb_audio_init(void)
-{
-       int result = usb_register(&usb_audio_driver);
-       if (result == 0) 
-               info(DRIVER_VERSION ":" DRIVER_DESC);
-       return result;
-}
-
-
-static void __exit usb_audio_cleanup(void)
-{
-       usb_deregister(&usb_audio_driver);
-}
-
-module_init(usb_audio_init);
-module_exit(usb_audio_cleanup);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/class/audio.h b/drivers/usb/class/audio.h
deleted file mode 100644 (file)
index 45916eb..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-#define CS_AUDIO_UNDEFINED             0x20
-#define CS_AUDIO_DEVICE                        0x21
-#define CS_AUDIO_CONFIGURATION         0x22
-#define CS_AUDIO_STRING                        0x23
-#define CS_AUDIO_INTERFACE             0x24
-#define CS_AUDIO_ENDPOINT              0x25
-
-#define HEADER                         0x01
-#define INPUT_TERMINAL                 0x02
-#define OUTPUT_TERMINAL                        0x03
-#define MIXER_UNIT                     0x04
-#define SELECTOR_UNIT                  0x05
-#define FEATURE_UNIT                   0x06
-#define PROCESSING_UNIT                        0x07
-#define EXTENSION_UNIT                 0x08
-
-#define AS_GENERAL                     0x01
-#define FORMAT_TYPE                    0x02
-#define FORMAT_SPECIFIC                        0x03
-
-#define EP_GENERAL                     0x01
-
-#define MAX_CHAN                       9
-#define MAX_FREQ                       16
-#define MAX_IFACE                      8
-#define MAX_FORMAT                     8
-#define MAX_ALT                                32      /* Sorry, we need quite a few for the Philips webcams */
-
-struct usb_audio_terminal
-{      
-       u8      flags;
-       u8      assoc;
-       u16     type;                   /* Mic etc */
-       u8      channels;
-       u8      source;
-       u16     chancfg;
-};
-
-struct usb_audio_format
-{
-       u8      type;
-       u8      channels;
-       u8      num_freq;
-       u8      sfz;
-       u8      bits;
-       u16     freq[MAX_FREQ];
-};
-
-struct usb_audio_interface
-{
-       u8      terminal;
-       u8      delay;
-       u16     num_formats;
-       u16     format_type;
-       u8      flags;
-       u8      idleconf;       /* Idle config */
-#define AU_IFACE_FOUND 1
-       struct  usb_audio_format format[MAX_FORMAT];
-};
-
-struct usb_audio_device
-{
-       struct list_head list;
-       u8      mixer;
-       u8      selector;
-       void    *irq_handle;
-       u8      num_channels;
-       u8      num_dsp_iface;
-       u8      channel_map[MAX_CHAN];
-       struct usb_audio_terminal terminal[MAX_CHAN];
-       struct usb_audio_interface interface[MAX_IFACE][MAX_ALT];
-};
-
-
-
-/* Audio Class specific Request Codes */
-
-#define SET_CUR    0x01
-#define GET_CUR    0x81
-#define SET_MIN    0x02
-#define GET_MIN    0x82
-#define SET_MAX    0x03
-#define GET_MAX    0x83
-#define SET_RES    0x04
-#define GET_RES    0x84
-#define SET_MEM    0x05
-#define GET_MEM    0x85
-#define GET_STAT   0xff
-
-/* Terminal Control Selectors */
-
-#define COPY_PROTECT_CONTROL       0x01
-
-/* Feature Unit Control Selectors */
-
-#define MUTE_CONTROL               0x01
-#define VOLUME_CONTROL             0x02
-#define BASS_CONTROL               0x03
-#define MID_CONTROL                0x04
-#define TREBLE_CONTROL             0x05
-#define GRAPHIC_EQUALIZER_CONTROL  0x06
-#define AUTOMATIC_GAIN_CONTROL     0x07
-#define DELAY_CONTROL              0x08
-#define BASS_BOOST_CONTROL         0x09
-#define LOUDNESS_CONTROL           0x0a
-
-/* Endpoint Control Selectors */
-
-#define SAMPLING_FREQ_CONTROL      0x01
-#define PITCH_CONTROL              0x02
index 97bdeb1..6dd339f 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb_cdc.h>
@@ -80,7 +81,7 @@ static struct usb_driver acm_driver;
 static struct tty_driver *acm_tty_driver;
 static struct acm *acm_table[ACM_TTY_MINORS];
 
-static DECLARE_MUTEX(open_sem);
+static DEFINE_MUTEX(open_mutex);
 
 #define ACM_READY(acm) (acm && acm->dev && acm->used)
 
@@ -431,8 +432,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
        int rv = -EINVAL;
        int i;
        dbg("Entering acm_tty_open.\n");
-       
-       down(&open_sem);
+
+       mutex_lock(&open_mutex);
 
        acm = acm_table[tty->index];
        if (!acm || !acm->dev)
@@ -474,14 +475,14 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
 done:
 err_out:
-       up(&open_sem);
+       mutex_unlock(&open_mutex);
        return rv;
 
 full_bailout:
        usb_kill_urb(acm->ctrlurb);
 bail_out:
        acm->used--;
-       up(&open_sem);
+       mutex_unlock(&open_mutex);
        return -EIO;
 }
 
@@ -507,7 +508,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
        if (!acm || !acm->used)
                return;
 
-       down(&open_sem);
+       mutex_lock(&open_mutex);
        if (!--acm->used) {
                if (acm->dev) {
                        acm_set_control(acm, acm->ctrlout = 0);
@@ -518,7 +519,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
                } else
                        acm_tty_unregister(acm);
        }
-       up(&open_sem);
+       mutex_unlock(&open_mutex);
 }
 
 static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1013,9 +1014,9 @@ static void acm_disconnect(struct usb_interface *intf)
                return;
        }
 
-       down(&open_sem);
+       mutex_lock(&open_mutex);
        if (!usb_get_intfdata(intf)) {
-               up(&open_sem);
+               mutex_unlock(&open_mutex);
                return;
        }
        acm->dev = NULL;
@@ -1045,11 +1046,11 @@ static void acm_disconnect(struct usb_interface *intf)
 
        if (!acm->used) {
                acm_tty_unregister(acm);
-               up(&open_sem);
+               mutex_unlock(&open_mutex);
                return;
        }
 
-       up(&open_sem);
+       mutex_unlock(&open_mutex);
 
        if (acm->tty)
                tty_hangup(acm->tty);
diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
deleted file mode 100644 (file)
index f13f004..0000000
+++ /dev/null
@@ -1,2153 +0,0 @@
-/*
-  usb-midi.c  --  USB-MIDI driver
-
-  Copyright (C) 2001 
-      NAGANO Daisuke <breeze.nagano@nifty.ne.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
-  the Free Software Foundation; either version 2, or (at your option)
-  any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  This driver is based on:
-    - 'Universal Serial Bus Device Class Definition for MIDI Device'
-    - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c
-    - alsa/lowlevel/pci/cs64xx.c
-    - umidi.c for NetBSD
- */
-
-/* ------------------------------------------------------------------------- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/poll.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <asm/semaphore.h>
-
-#include "usb-midi.h"
-
-/* ------------------------------------------------------------------------- */
-
-/* More verbose on syslog */
-#undef MIDI_DEBUG
-
-#define MIDI_IN_BUFSIZ 1024
-
-#define HAVE_SUPPORT_USB_MIDI_CLASS
-
-#undef HAVE_SUPPORT_ALSA
-
-/* ------------------------------------------------------------------------- */
-
-static int singlebyte = 0;
-module_param(singlebyte, int, 0);
-MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet");
-
-static int maxdevices = 4;
-module_param(maxdevices, int, 0);
-MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device");
-
-static int uvendor     = -1;
-module_param(uvendor, int, 0);
-MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface");
-
-static int uproduct    = -1;
-module_param(uproduct, int, 0);
-MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface");
-
-static int uinterface  = -1;
-module_param(uinterface, int, 0);
-MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface");
-
-static int ualt        = -1;
-module_param(ualt, int, 0);
-MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface");
-
-static int umin        = -1;
-module_param(umin, int, 0);
-MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface");
-
-static int umout       = -1;
-module_param(umout, int, 0);
-MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface");
-
-static int ucable      = -1;
-module_param(ucable, int, 0);
-MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface");
-
-/** Note -- the usb_string() returns only Latin-1 characters.
- * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or
- * unicode16LE-to-JIS routine is needed to wrap around usb_get_string().
- **/
-static unsigned short ulangid      = 0x0409; /** 0x0411 for Japanese **/
-module_param(ulangid, ushort, 0);
-MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices");
-
-MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>");
-MODULE_DESCRIPTION("USB-MIDI driver");
-MODULE_LICENSE("GPL");
-
-/* ------------------------------------------------------------------------- */
-
-/** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/
-
-#define MS_DESCRIPTOR_UNDEFINED        0
-#define MS_HEADER              1
-#define MIDI_IN_JACK           2
-#define MIDI_OUT_JACK          3
-/* Spec reads: ELEMENT */
-#define ELEMENT_DESCRIPTOR     4
-
-#define MS_HEADER_LENGTH       7
-
-/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/
-
-#define DESCRIPTOR_UNDEFINED   0
-/* Spec reads: MS_GENERAL */
-#define MS_GENERAL_ENDPOINT    1
-
-/** MIDIStreaming MIDI IN and OUT Jack Types **/
-
-#define JACK_TYPE_UNDEFINED    0
-/* Spec reads: EMBEDDED */
-#define EMBEDDED_JACK          1
-/* Spec reads: EXTERNAL */
-#define EXTERNAL_JACK          2
-
-
-/* structure summary
-  
-      usb_midi_state     usb_device
-       |         |
-      *|        *|       per ep
-     in_ep     out_ep
-       |         |
-      *|        *|       per cable
-      min       mout
-       |         |       (cable to device pairing magic)
-       |         |
-       usb_midi_dev      dev_id (major,minor) == file->private_data
-
-*/
-
-/* usb_midi_state: corresponds to a USB-MIDI module */
-struct usb_midi_state {
-       struct list_head   mididev;
-       
-       struct usb_device *usbdev;
-       
-       struct list_head   midiDevList;
-       struct list_head   inEndpointList;
-       struct list_head   outEndpointList;
-       
-       spinlock_t         lock;
-       
-       unsigned int       count; /* usage counter */
-};
-
-/* midi_out_endpoint: corresponds to an output endpoint */
-struct midi_out_endpoint {
-       struct list_head  list;
-       
-       struct usb_device *usbdev;
-       int                endpoint;
-       spinlock_t         lock;
-       wait_queue_head_t  wait;
-       
-       unsigned char     *buf;
-       int                bufWrPtr;
-       int                bufSize;
-       
-       struct urb       *urb;
-};
-
-/* midi_in_endpoint: corresponds to an input endpoint */
-struct midi_in_endpoint {
-       struct list_head   list;
-
-       struct usb_device *usbdev;
-       int                endpoint;
-       spinlock_t         lock;
-       wait_queue_head_t  wait;
-
-       struct usb_mididev *cables[16]; // cables open for read
-       int                 readers;    // number of cables open for read
-
-       struct urb        *urb;
-       unsigned char     *recvBuf;
-       int                recvBufSize;
-       int                urbSubmitted;        //FIXME: == readers > 0
-};
-
-/* usb_mididev: corresponds to a logical device */
-struct usb_mididev {
-       struct list_head       list;
-
-       struct usb_midi_state *midi;
-       int                    dev_midi;
-       mode_t                 open_mode;
-
-       struct {
-               struct midi_in_endpoint *ep;
-               int              cableId;
-               
-// as we are pushing data from usb_bulk_read to usb_midi_read,
-// we need a larger, cyclic buffer here.
-               unsigned char    buf[MIDI_IN_BUFSIZ];
-               int              bufRdPtr;
-               int              bufWrPtr;
-               int              bufRemains;
-       } min;
-
-       struct {
-               struct midi_out_endpoint *ep;
-               int              cableId;
-               
-               unsigned char    buf[3];
-               int              bufPtr;
-               int              bufRemains;
-               
-               int              isInExclusive;
-               unsigned char    lastEvent;
-       } mout;
-
-       int singlebyte;
-};
-
-/** Map the high nybble of MIDI voice messages to number of Message bytes.
- * High nyble ranges from 0x8 to 0xe
- */
-
-static int remains_80e0[] = {
-       3,      /** 0x8X Note Off **/
-       3,      /** 0x9X Note On **/
-       3,      /** 0xAX Poly-key pressure **/
-       3,      /** 0xBX Control Change **/
-       2,      /** 0xCX Program Change **/
-       2,      /** 0xDX Channel pressure **/
-       3       /** 0xEX PitchBend Change **/
-};
-
-/** Map the messages to a number of Message bytes.
- *
- **/
-static int remains_f0f6[] = {
-       0,      /** 0xF0 **/
-       2,      /** 0XF1 **/
-       3,      /** 0XF2 **/
-       2,      /** 0XF3 **/
-       2,      /** 0XF4 (Undefined by MIDI Spec, and subject to change) **/
-       2,      /** 0XF5 (Undefined by MIDI Spec, and subject to change) **/
-       1       /** 0XF6 **/
-};
-
-/** Map the messages to a CIN (Code Index Number).
- *
- **/
-static int cin_f0ff[] = {
-       4,      /** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */
-       2,      /** 0xF1 **/
-       3,      /** 0xF2 **/
-       2,      /** 0xF3 **/
-       2,      /** 0xF4 **/
-       2,      /** 0xF5 **/
-       5,      /** 0xF6 **/
-       5,      /** 0xF7 End of System Exclusive Message (May be 6 or 7) **/
-       5,      /** 0xF8 **/
-       5,      /** 0xF9 **/
-       5,      /** 0xFA **/
-       5,      /** 0xFB **/
-       5,      /** 0xFC **/
-       5,      /** 0xFD **/
-       5,      /** 0xFE **/
-       5       /** 0xFF **/
-};
-
-/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0)
- * to the number of bytes of valid MIDI data.
- *
- * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0.
- *
- **/
-static int cin_to_len[] = {
-       0, 0, 2, 3,
-       3, 1, 2, 3,
-       3, 3, 3, 3,
-       2, 2, 3, 1
-};
-
-
-/* ------------------------------------------------------------------------- */
-
-static struct list_head mididevs = LIST_HEAD_INIT(mididevs);
-
-static DECLARE_MUTEX(open_sem);
-static DECLARE_WAIT_QUEUE_HEAD(open_wait);
-
-
-/* ------------------------------------------------------------------------- */
-
-static void usb_write_callback(struct urb *urb, struct pt_regs *regs)
-{
-       struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context;
-
-       if ( waitqueue_active( &ep->wait ) )
-               wake_up_interruptible( &ep->wait );
-}
-
-
-static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len )
-{
-       struct usb_device *d;
-       int pipe;
-       int ret = 0;
-       int status;
-       int maxretry = 50;
-       
-       DECLARE_WAITQUEUE(wait,current);
-       init_waitqueue_head(&ep->wait);
-
-       d = ep->usbdev;
-       pipe = usb_sndbulkpipe(d, ep->endpoint);
-       usb_fill_bulk_urb( ep->urb, d, pipe, (unsigned char*)buf, len,
-                      usb_write_callback, ep );
-
-       status = usb_submit_urb(ep->urb, GFP_KERNEL);
-    
-       if (status) {
-               printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status);
-               ret = -EIO;
-               goto error;
-       }
-
-       add_wait_queue( &ep->wait, &wait );
-       set_current_state( TASK_INTERRUPTIBLE );
-
-       while( ep->urb->status == -EINPROGRESS ) {
-               if ( maxretry-- < 0 ) {
-                       printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n");
-                       ret = -ETIME;
-                       break;
-               }
-               interruptible_sleep_on_timeout( &ep->wait, 10 );
-       }
-       set_current_state( TASK_RUNNING );
-       remove_wait_queue( &ep->wait, &wait );
-
-error:
-       return ret;
-}
-
-
-/** Copy data from URB to In endpoint buf.
- * Discard if CIN == 0 or CIN = 1.
- *
- *
- **/
-
-static void usb_bulk_read(struct urb *urb, struct pt_regs *regs)
-{
-       struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
-       unsigned char *data = urb->transfer_buffer;
-       int i, j, wake;
-
-       if ( !ep->urbSubmitted ) {
-               return;
-       }
-
-       if ( (urb->status == 0) && (urb->actual_length > 0) ) {
-               wake = 0;
-               spin_lock( &ep->lock );
-
-               for(j = 0; j < urb->actual_length; j += 4) {
-                       int cin = (data[j]>>0)&0xf;
-                       int cab = (data[j]>>4)&0xf;
-                       struct usb_mididev *cable = ep->cables[cab];
-                       if ( cable ) {
-                               int len = cin_to_len[cin]; /** length of MIDI data **/
-                               for (i = 0; i < len; i++) {
-                                       cable->min.buf[cable->min.bufWrPtr] = data[1+i+j];
-                                       cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
-                                       if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
-                                               cable->min.bufRemains += 1;
-                                       else /** need to drop data **/
-                                               cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
-                                       wake = 1;
-                               }
-                       }
-               }
-
-               spin_unlock ( &ep->lock );
-               if ( wake ) {
-                       wake_up( &ep->wait );
-               }
-       }
-
-       /* urb->dev must be reinitialized on 2.4.x kernels */
-       urb->dev = ep->usbdev;
-
-       urb->actual_length = 0;
-       usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-
-
-/* ------------------------------------------------------------------------- */
-
-/* This routine must be called with spin_lock */
-
-/** Wrapper around usb_write().
- *  This routine must be called with spin_lock held on ep.
- *  Called by midiWrite(), putOneMidiEvent(), and  usb_midi_write();
- **/
-static int flush_midi_buffer( struct midi_out_endpoint *ep )
-{
-       int ret=0;
-
-       if ( ep->bufWrPtr > 0 ) {
-               ret = usb_write( ep, ep->buf, ep->bufWrPtr );
-               ep->bufWrPtr = 0;
-       }
-
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-/** Given a MIDI Event, determine size of data to be attached to 
- * USB-MIDI packet.
- * Returns 1, 2 or 3.
- * Called by midiWrite();
- * Uses remains_80e0 and remains_f0f6;
- **/
-static int get_remains(int event)
-{
-       int ret;
-
-       if ( event  < 0x80 ) {
-               ret = 1;
-       } else if ( event < 0xf0 ) {
-               ret = remains_80e0[((event-0x80)>>4)&0x0f];
-       } else if ( event < 0xf7 ) {
-               ret = remains_f0f6[event-0xf0];
-       } else {
-               ret = 1;
-       }
-
-       return ret;
-}
-
-/** Given the output MIDI data in the output buffer, computes a reasonable 
- * CIN.
- * Called by putOneMidiEvent().
- **/
-static int get_CIN( struct usb_mididev *m )
-{
-       int cin;
-
-       if ( m->mout.buf[0] == 0xf7 ) {
-               cin = 5;
-       }
-       else if ( m->mout.buf[1] == 0xf7 ) {
-               cin = 6;
-       }
-       else if ( m->mout.buf[2] == 0xf7 ) {
-               cin = 7;
-       }
-       else {
-               if ( m->mout.isInExclusive == 1 ) {
-                       cin = 4;
-               } else if ( m->mout.buf[0] < 0x80 ) {
-                       /** One byte that we know nothing about. **/
-                       cin = 0xF; 
-               } else if ( m->mout.buf[0] < 0xf0 ) {
-                       /** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/
-                       cin = (m->mout.buf[0]>>4)&0x0f; 
-               }
-               else {
-                       /** Special lookup table exists for real-time events. **/
-                       cin = cin_f0ff[m->mout.buf[0]-0xf0];
-               }
-       }
-
-       return cin;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-
-/** Move data to USB endpoint buffer.
- *
- **/
-static int put_one_midi_event(struct usb_mididev *m)
-{
-       int cin;
-       unsigned long flags;
-       struct midi_out_endpoint *ep = m->mout.ep;
-       int ret=0;
-
-       cin = get_CIN( m );
-       if ( cin > 0x0f || cin < 0 ) {
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave( &ep->lock, flags );
-       ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin;
-       ep->buf[ep->bufWrPtr++] = m->mout.buf[0];
-       ep->buf[ep->bufWrPtr++] = m->mout.buf[1];
-       ep->buf[ep->bufWrPtr++] = m->mout.buf[2];
-       if ( ep->bufWrPtr >= ep->bufSize ) {
-               ret = flush_midi_buffer( ep );
-       }
-       spin_unlock_irqrestore( &ep->lock, flags);
-
-       m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0;
-       m->mout.bufPtr = 0;
-
-       return ret;
-}
-
-/** Write the MIDI message v on the midi device.
- *  Called by usb_midi_write();
- *  Responsible for packaging a MIDI data stream into USB-MIDI packets.
- **/
-
-static int midi_write( struct usb_mididev *m, int v )
-{
-       unsigned long flags;
-       struct midi_out_endpoint *ep = m->mout.ep;
-       int ret=0;
-       unsigned char c = (unsigned char)v;
-       unsigned char sysrt_buf[4];
-
-       if ( m->singlebyte != 0 ) {
-               /** Simple code to handle the single-byte USB-MIDI protocol. */
-               spin_lock_irqsave( &ep->lock, flags );
-               if ( ep->bufWrPtr+4 > ep->bufSize ) {
-                       ret = flush_midi_buffer( ep );
-                       if ( !ret ) {
-                               spin_unlock_irqrestore( &ep->lock, flags );
-                               return ret;
-                       }
-               }
-               ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) |  0x0f; /* single byte */
-               ep->buf[ep->bufWrPtr++] = c;
-               ep->buf[ep->bufWrPtr++] = 0;
-               ep->buf[ep->bufWrPtr++] = 0;
-               if ( ep->bufWrPtr >= ep->bufSize ) {
-                       ret = flush_midi_buffer( ep );
-               }
-               spin_unlock_irqrestore( &ep->lock, flags );
-
-               return ret;
-       }
-       /** Normal USB-MIDI protocol begins here. */
-
-       if ( c > 0xf7 ) {       /* system: Realtime messages */
-               /** Realtime messages are written IMMEDIATELY. */
-               sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f;
-               sysrt_buf[1] = c;
-               sysrt_buf[2] = 0;
-               sysrt_buf[3] = 0;
-               spin_lock_irqsave( &ep->lock, flags );
-               ret = usb_write( ep, sysrt_buf, 4 );
-               spin_unlock_irqrestore( &ep->lock, flags );
-               /* m->mout.lastEvent = 0; */
-
-               return ret;
-       }
-
-       if ( c >= 0x80 ) {
-               if ( c < 0xf0 ) {
-                       m->mout.lastEvent = c;
-                       m->mout.isInExclusive = 0;
-                       m->mout.bufRemains = get_remains(c);
-               } else if ( c == 0xf0 ) {
-                       /* m->mout.lastEvent = 0; */
-                       m->mout.isInExclusive = 1;
-                       m->mout.bufRemains = get_remains(c);
-               } else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) {
-                       /* m->mout.lastEvent = 0; */
-                       m->mout.isInExclusive = 0;
-                       m->mout.bufRemains = 1;
-               } else if ( c > 0xf0 ) {
-                       /* m->mout.lastEvent = 0; */
-                       m->mout.isInExclusive = 0;
-                       m->mout.bufRemains = get_remains(c);
-               }
-    
-       } else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) {
-               if ( m->mout.lastEvent == 0 ) {
-                       return 0; /* discard, waiting for the first event */
-               }
-               /** track status **/
-               m->mout.buf[0] = m->mout.lastEvent;
-               m->mout.bufPtr = 1;
-               m->mout.bufRemains = get_remains(m->mout.lastEvent)-1;
-       }
-  
-       m->mout.buf[m->mout.bufPtr++] = c;
-       m->mout.bufRemains--;
-       if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) {
-               ret = put_one_midi_event(m);
-       }
-
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic contract: Used to change the current read/write position in a file.
- *  On success, the non-negative position is reported.
- *  On failure, the negative of an error code is reported.
- *
- *  Because a MIDIStream is not a file, all seek operations are doomed to fail.
- *
- **/
-static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin)
-{
-       /** Tell user you cannot seek on a PIPE-like device. **/
-       return -ESPIPE;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract: Block until count bytes have been read or an error occurs.
- *
- **/
-
-static ssize_t usb_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-       struct midi_in_endpoint *ep = m->min.ep;
-       ssize_t ret;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if ( !access_ok(VERIFY_READ, buffer, count) ) {
-               return -EFAULT;
-       }
-       if ( count == 0 ) {
-               return 0;
-       }
-
-       add_wait_queue( &ep->wait, &wait );
-       ret = 0;
-       while( count > 0 ) {
-               int cnt;
-               int d = (int)count;
-
-               cnt = m->min.bufRemains;
-               if ( cnt > d ) {
-                       cnt = d;
-               }
-
-               if ( cnt <= 0 ) {
-                       if ( file->f_flags & O_NONBLOCK ) {
-                               if (!ret) 
-                                       ret = -EAGAIN;
-                               break;
-                       }
-                       __set_current_state(TASK_INTERRUPTIBLE);
-                       schedule();
-                       if (signal_pending(current)) {
-                               if(!ret)
-                                       ret=-ERESTARTSYS;
-                               break;
-                       }
-                       continue;
-               }
-
-               {
-                       int i;
-                       unsigned long flags; /* used to synchronize access to the endpoint */
-                       spin_lock_irqsave( &ep->lock, flags );
-                       for (i = 0; i < cnt; i++) {
-                               if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) {
-                                       if ( !ret )
-                                               ret = -EFAULT;
-                                       break;
-                               }
-                               m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
-                               m->min.bufRemains -= 1;
-                       }
-                       spin_unlock_irqrestore( &ep->lock, flags );
-               }
-
-               count-=cnt;
-               buffer+=cnt;
-               ret+=cnt;
-
-               break;
-       }
-
-       remove_wait_queue( &ep->wait, &wait );
-       set_current_state(TASK_RUNNING);
-
-       return ret;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic Contract: Take MIDI data byte-by-byte and pass it to
- *  writeMidi() which packages MIDI data into USB-MIDI stream.
- *  Then flushMidiData() is called to ensure all bytes have been written
- *  in a timely fashion.
- *
- **/
-
-static ssize_t usb_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-       ssize_t ret;
-       unsigned long int flags;
-
-       if ( !access_ok(VERIFY_READ, buffer, count) ) {
-               return -EFAULT;
-       }
-       if ( count == 0 ) {
-               return 0;
-       }
-
-       ret = 0;
-       while( count > 0 ) {
-               unsigned char c;
-
-               if (copy_from_user((unsigned char *)&c, buffer, 1)) {
-                       if ( ret == 0 )
-                               ret = -EFAULT;
-                       break;
-               }
-               if( midi_write(m, (int)c) ) {
-                       if ( ret == 0 )
-                               ret = -EFAULT;
-                       break;
-               }
-               count--;
-               buffer++;
-               ret++;
-       }
-
-       spin_lock_irqsave( &m->mout.ep->lock, flags );
-       if ( flush_midi_buffer(m->mout.ep) < 0 ) {
-               ret = -EFAULT;
-       }
-       spin_unlock_irqrestore( &m->mout.ep->lock, flags );
-
-       return ret;
-}
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract:  Wait (spin) until ready to read or write on the file.
- *
- **/
-static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-       struct midi_in_endpoint *iep = m->min.ep;
-       struct midi_out_endpoint *oep = m->mout.ep;
-       unsigned long flags;
-       unsigned int mask = 0;
-  
-       if ( file->f_mode & FMODE_READ ) {
-               poll_wait( file, &iep->wait, wait );
-               spin_lock_irqsave( &iep->lock, flags );
-               if ( m->min.bufRemains > 0 )
-                       mask |= POLLIN | POLLRDNORM;
-               spin_unlock_irqrestore( &iep->lock, flags );
-       }
-
-       if ( file->f_mode & FMODE_WRITE ) {
-               poll_wait( file, &oep->wait, wait );
-               spin_lock_irqsave( &oep->lock, flags );
-               if ( oep->bufWrPtr < oep->bufSize )
-                       mask |= POLLOUT | POLLWRNORM;
-               spin_unlock_irqrestore( &oep->lock, flags );
-       }
-
-       return mask;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract: This is always the first operation performed on the
- * device node. If no method is defined, the open succeeds without any
- * notification given to the module.
- *
- **/
-
-static int usb_midi_open(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       DECLARE_WAITQUEUE(wait, current);
-       struct usb_midi_state *s;
-       struct usb_mididev    *m;
-       unsigned long flags;
-       int succeed = 0;
-
-#if 0
-       printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor);
-#endif
-
-       for(;;) {
-               down(&open_sem);
-               list_for_each_entry(s, &mididevs, mididev) {
-                       list_for_each_entry(m, &s->midiDevList, list) {
-                               if ( !((m->dev_midi ^ minor) & ~0xf) )
-                                       goto device_found;
-                       }
-               }
-               up(&open_sem);
-               return -ENODEV;
-
-       device_found:
-               if ( !s->usbdev ) {
-                       up(&open_sem);
-                       return -EIO;
-               }
-               if ( !(m->open_mode & file->f_mode) ) {
-                       break;
-               }
-               if ( file->f_flags & O_NONBLOCK ) {
-                       up(&open_sem);
-                       return -EBUSY;
-               }
-               __set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue( &open_wait, &wait );
-               up(&open_sem);
-               schedule();
-               remove_wait_queue( &open_wait, &wait );
-               if ( signal_pending(current) ) {
-                       return -ERESTARTSYS;
-               }
-       }
-
-       file->private_data = m;
-       spin_lock_irqsave( &s->lock, flags );
-
-       if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) {
-               //FIXME: intented semantics unclear here
-               m->min.bufRdPtr       = 0;
-               m->min.bufWrPtr       = 0;
-               m->min.bufRemains     = 0;
-               spin_lock_init(&m->min.ep->lock);
-
-               m->mout.bufPtr        = 0;
-               m->mout.bufRemains    = 0;
-               m->mout.isInExclusive = 0;
-               m->mout.lastEvent     = 0;
-               spin_lock_init(&m->mout.ep->lock);
-       }
-
-       if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) {
-               unsigned long int flagsep;
-               spin_lock_irqsave( &m->min.ep->lock, flagsep );
-               m->min.ep->cables[m->min.cableId] = m;
-               m->min.ep->readers += 1;
-               m->min.bufRdPtr       = 0;
-               m->min.bufWrPtr       = 0;
-               m->min.bufRemains     = 0;
-               spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
-
-               if ( !(m->min.ep->urbSubmitted)) {
-
-                       /* urb->dev must be reinitialized on 2.4.x kernels */
-                       m->min.ep->urb->dev = m->min.ep->usbdev;
-
-                       if ( usb_submit_urb(m->min.ep->urb, GFP_ATOMIC) ) {
-                               printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n");
-                       }
-                       m->min.ep->urbSubmitted = 1;
-               }
-               m->open_mode |= FMODE_READ;
-               succeed = 1;
-       }
-
-       if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) {
-               m->mout.bufPtr        = 0;
-               m->mout.bufRemains    = 0;
-               m->mout.isInExclusive = 0;
-               m->mout.lastEvent     = 0;
-               m->open_mode |= FMODE_WRITE;
-               succeed = 1;
-       }
-
-       spin_unlock_irqrestore( &s->lock, flags );
-
-       s->count++;
-       up(&open_sem);
-
-       /** Changed to prevent extra increments to USE_COUNT. **/
-       if (!succeed) {
-               return -EBUSY;
-       }
-
-#if 0
-       printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor);
-#endif
-
-       return nonseekable_open(inode, file); /** Success. **/
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic contract: Close an opened file and deallocate anything we allocated.
- *  Like open(), this can be missing. If open set file->private_data,
- *  release() must clear it.
- *
- **/
-
-static int usb_midi_release(struct inode *inode, struct file *file)
-{
-       struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-       struct usb_midi_state *s = (struct usb_midi_state *)m->midi;
-
-#if 0
-       printk(KERN_INFO "usb-midi: Close.\n");
-#endif
-
-       down(&open_sem);
-
-       if ( m->open_mode & FMODE_WRITE ) {
-               m->open_mode &= ~FMODE_WRITE;
-               usb_kill_urb( m->mout.ep->urb );
-       }
-
-       if ( m->open_mode & FMODE_READ ) {
-               unsigned long int flagsep;
-               spin_lock_irqsave( &m->min.ep->lock, flagsep );
-                m->min.ep->cables[m->min.cableId] = NULL; // discard cable
-                m->min.ep->readers -= 1;
-               m->open_mode &= ~FMODE_READ;
-               if ( m->min.ep->readers == 0 &&
-                     m->min.ep->urbSubmitted ) {
-                       m->min.ep->urbSubmitted = 0;
-                       usb_kill_urb(m->min.ep->urb);
-               }
-               spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
-       }
-
-       s->count--;
-
-       up(&open_sem);
-       wake_up(&open_wait);
-
-       file->private_data = NULL;
-       return 0;
-}
-
-static struct file_operations usb_midi_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       usb_midi_llseek,
-       .read =         usb_midi_read,
-       .write =        usb_midi_write,
-       .poll =         usb_midi_poll,
-       .open =         usb_midi_open,
-       .release =      usb_midi_release,
-};
-
-/* ------------------------------------------------------------------------- */
-
-/** Returns filled midi_in_endpoint structure or null on failure.
- *
- * Parameters:
- *     d        - a usb_device
- *     endPoint - An usb endpoint in the range 0 to 15.
- * Called by allocUsbMidiDev();
- *
- **/
-
-static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint )
-{
-       struct midi_in_endpoint *ep;
-       int bufSize;
-       int pipe;
-
-       endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */
-
-       pipe =  usb_rcvbulkpipe( d, endPoint );
-       bufSize = usb_maxpacket( d, pipe, 0 );
-       /* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */
-
-       ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL);
-       if ( !ep ) {
-               printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n");
-               return NULL;
-       }
-       memset( ep, 0, sizeof(struct midi_in_endpoint) );
-//      this sets cables[] and readers to 0, too.
-//      for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable
-//      ep->readers = 0;
-
-       ep->endpoint = endPoint;
-
-       ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL);
-       if ( !ep->recvBuf ) {
-               printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n");
-               kfree(ep);
-               return NULL;
-       }
-
-       ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */
-       if ( !ep->urb ) {
-               printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n");
-               kfree(ep->recvBuf);
-               kfree(ep);
-               return NULL;
-       }
-       usb_fill_bulk_urb( ep->urb, d, 
-                      usb_rcvbulkpipe(d, endPoint),
-                      (unsigned char *)ep->recvBuf, bufSize,
-                      usb_bulk_read, ep );
-
-       /* ep->bufRdPtr     = 0; */
-       /* ep->bufWrPtr     = 0; */
-       /* ep->bufRemains   = 0; */
-       /* ep->urbSubmitted = 0; */
-       ep->recvBufSize  = bufSize;
-
-       init_waitqueue_head(&ep->wait);
-
-       return ep;
-}
-
-static int remove_midi_in_endpoint( struct midi_in_endpoint *min )
-{
-       usb_kill_urb( min->urb );
-       usb_free_urb( min->urb );
-       kfree( min->recvBuf );
-       kfree( min );
-
-       return 0;
-}
-
-/** Returns filled midi_out_endpoint structure or null on failure.
- *
- * Parameters:
- *     d        - a usb_device
- *     endPoint - An usb endpoint in the range 0 to 15.
- * Called by allocUsbMidiDev();
- *
- **/
-static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint )
-{
-       struct midi_out_endpoint *ep = NULL;
-       int pipe;
-       int bufSize;
-
-       endPoint &= 0x0f;
-       pipe =  usb_sndbulkpipe( d, endPoint );
-       bufSize = usb_maxpacket( d, pipe, 1 );
-
-       ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL);
-       if ( !ep ) {
-               printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n");
-               return NULL;
-       }
-       memset( ep, 0, sizeof(struct midi_out_endpoint) );
-
-       ep->endpoint = endPoint;
-       ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
-       if ( !ep->buf ) {
-               printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n");
-               kfree(ep);
-               return NULL;
-       }
-
-       ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */
-       if ( !ep->urb ) {
-               printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n");
-               kfree(ep->buf);
-               kfree(ep);
-               return NULL;
-       }
-
-       ep->bufSize       = bufSize;
-       /* ep->bufWrPtr      = 0; */
-
-       init_waitqueue_head(&ep->wait);
-
-       return ep;
-}
-
-
-static int remove_midi_out_endpoint( struct midi_out_endpoint *mout )
-{
-       usb_kill_urb( mout->urb );
-       usb_free_urb( mout->urb );
-       kfree( mout->buf );
-       kfree( mout );
-
-       return 0;
-}
-
-
-/** Returns a filled usb_mididev structure, registered as a Linux MIDI device.
- *
- * Returns null if memory is not available or the device cannot be registered.
- * Called by allocUsbMidiDev();
- *
- **/
-static struct usb_mididev *allocMidiDev(
-       struct usb_midi_state *s,
-       struct midi_in_endpoint *min,
-       struct midi_out_endpoint *mout,
-       int inCableId,
-       int outCableId )
-{
-       struct usb_mididev *m;
-
-       m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL);
-       if (!m) {
-               printk(KERN_ERR "usbmidi: no memory for midi device\n");
-               return NULL;
-       }
-
-       memset(m, 0, sizeof(struct usb_mididev));
-
-       if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) {
-               printk(KERN_ERR "usbmidi: cannot register midi device\n");
-               kfree(m);
-               return NULL;
-       }
-
-       m->midi               = s;
-       /* m->open_mode          = 0; */
-
-       if ( min ) {
-               m->min.ep             = min;
-               m->min.ep->usbdev     = s->usbdev;
-               m->min.cableId        = inCableId;
-       }
-       /* m->min.bufPtr         = 0; */
-       /* m->min.bufRemains     = 0; */
-
-       if ( mout ) {
-               m->mout.ep            = mout;
-               m->mout.ep->usbdev    = s->usbdev;
-               m->mout.cableId       = outCableId;
-       }
-       /* m->mout.bufPtr        = 0; */
-       /* m->mout.bufRemains    = 0; */
-       /* m->mout.isInExclusive = 0; */
-       /* m->mout.lastEvent     = 0; */
-
-       m->singlebyte         = singlebyte;
-
-       return m;
-}
-
-
-static void release_midi_device( struct usb_midi_state *s )
-{
-       struct usb_mididev *m;
-       struct midi_in_endpoint *min;
-       struct midi_out_endpoint *mout;
-
-       if ( s->count > 0 ) {
-               up(&open_sem);
-               return;
-       }
-       up( &open_sem );
-       wake_up( &open_wait );
-
-       while(!list_empty(&s->inEndpointList)) {
-               min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list);
-               list_del(&min->list);
-               remove_midi_in_endpoint(min);
-       }
-
-       while(!list_empty(&s->outEndpointList)) {
-               mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list);
-               list_del(&mout->list);
-               remove_midi_out_endpoint(mout);
-       }
-
-       while(!list_empty(&s->midiDevList)) {
-               m = list_entry(s->midiDevList.next, struct usb_mididev, list);
-               list_del(&m->list);
-               kfree(m);
-       }
-
-       kfree(s);
-
-       return;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/** Utility routine to find a descriptor in a dump of many descriptors.
- * Returns start of descriptor or NULL if not found. 
- * descStart pointer to list of interfaces.
- * descLength length (in bytes) of dump
- * after (ignored if NULL) this routine returns only descriptors after "after"
- * dtype (mandatory) The descriptor type.
- * iface (ignored if -1) returns descriptor at/following given interface
- * altSetting (ignored if -1) returns descriptor at/following given altSetting
- *
- *
- *  Called by parseDescriptor(), find_csinterface_descriptor();
- *
- */
-static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting )
-{
-       unsigned char *p, *end, *next;
-       int interfaceNumber = -1, altSet = -1;
-
-       p = descStart;
-       end = p + descLength;
-       for( ; p < end; ) {
-               if ( p[0] < 2 )
-                       return NULL;
-               next = p + p[0];
-               if ( next > end )
-                       return NULL;
-               if ( p[1] == USB_DT_INTERFACE ) {
-                       if ( p[0] < USB_DT_INTERFACE_SIZE )
-                               return NULL;
-                       interfaceNumber = p[2];
-                       altSet = p[3];
-               }
-               if ( p[1] == dtype &&
-                    ( !after || ( p > (unsigned char *)after) ) &&
-                    ( ( iface == -1) || (iface == interfaceNumber) ) &&
-                    ( (altSetting == -1) || (altSetting == altSet) )) {
-                       return p;
-               }
-               p = next;
-       }
-       return NULL;
-}
-
-/** Utility to find a class-specific interface descriptor.
- *  dsubtype is a descriptor subtype
- *  Called by parseDescriptor();
- **/
-static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting)
-{
-       unsigned char *p;
-  
-       p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting );
-       while ( p ) {
-               if ( p[0] >= 3 && p[2] == dsubtype )
-                       return p;
-               p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, 
-                                    iface, altSetting );
-       }
-       return NULL;
-}
-
-
-/** The magic of making a new usb_midi_device from config happens here.
- *
- * The caller is responsible for free-ing this return value (if not NULL).
- *
- **/
-static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks)
-{
-       struct usb_midi_device *u;
-       unsigned char *p1;
-       unsigned char *p2;
-       unsigned char *next;
-       int iep, oep;
-       int length;
-       unsigned long longBits;
-       int pins, nbytes, offset, shift, jack;
-#ifdef HAVE_JACK_STRINGS
-       /** Jacks can have associated names.  **/
-       unsigned char jack2string[256];
-#endif
-
-       u = NULL;
-       /* find audiocontrol interface */
-       p1 = find_csinterface_descriptor( buffer, bufSize, NULL,
-                                         MS_HEADER, ifnum, altSetting);
-
-       if ( !p1 ) {
-               goto error_end;
-       }
-
-       if ( p1[0] < MS_HEADER_LENGTH ) {
-               goto error_end;
-       }
-
-       /* Assume success. Since the device corresponds to USB-MIDI spec, we assume
-          that the rest of the USB 2.0 spec is obeyed. */
-
-       u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL );
-       if ( !u ) {
-               return NULL;
-       }
-       u->deviceName = NULL;
-       u->idVendor = le16_to_cpu(d->descriptor.idVendor);
-       u->idProduct = le16_to_cpu(d->descriptor.idProduct);
-       u->interface = ifnum;
-       u->altSetting = altSetting;
-       u->in[0].endpoint = -1;
-       u->in[0].cableId = -1;
-       u->out[0].endpoint = -1;
-       u->out[0].cableId = -1;
-
-
-       printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n",
-              (p1[4] >> 4) * 10 + (p1[4] & 0x0f ),
-              (p1[3] >> 4) * 10 + (p1[3] & 0x0f )
-               );
-
-       length = p1[5] | (p1[6] << 8);
-
-#ifdef HAVE_JACK_STRINGS
-       memset(jack2string, 0, sizeof(unsigned char) * 256);
-#endif
-
-       length -= p1[0];
-       for (p2 = p1 + p1[0]; length > 0; p2 = next) {
-               next = p2 + p2[0];
-               length -= p2[0];
-
-               if (p2[0] < 2 )
-                       break;
-               if (p2[1] != USB_DT_CS_INTERFACE)
-                       break;
-               if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) {
-                       jack = p2[4];
-#ifdef HAVE_JACK_STRINGS
-                       jack2string[jack] = p2[5];
-#endif
-                       printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n",
-                              jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" );
-               } else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) {
-                       pins = p2[5];
-                       if ( p2[0] < (6 + 2 * pins) )
-                               continue;
-                       jack = p2[4];
-#ifdef HAVE_JACK_STRINGS
-                       jack2string[jack] = p2[5 + 2 * pins];
-#endif
-                       printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n",
-                              jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins );
-               } else if ( p2[2] == ELEMENT_DESCRIPTOR  && p2[0]  >= 10) {
-                       pins = p2[4];
-                       if ( p2[0] < (9 + 2 * pins ) )
-                               continue;
-                       nbytes = p2[8 + 2 * pins ];
-                       if ( p2[0] < (10 + 2 * pins + nbytes) )
-                               continue;
-                       longBits = 0L;
-                       for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) {
-                               longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift;
-                       }
-                       jack = p2[3];
-#ifdef HAVE_JACK_STRINGS
-                       jack2string[jack] = p2[9 + 2 * pins + nbytes];
-#endif
-                       printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n",
-                              jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits );
-               } else {
-               }
-       }
-
-       iep=0;
-       oep=0;
-
-       if (quirks==0) {
-               /* MIDISTREAM */
-               p2 = NULL;
-               for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
-                                         ifnum, altSetting ); p1; p1 = next ) {
-                       next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
-                                              ifnum, altSetting ); 
-                       p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT,
-                                            ifnum, altSetting ); 
-
-                       if ( p2 && next && ( p2 > next ) )
-                               p2 = NULL;
-
-                       if ( p1[0] < 9 || !p2 || p2[0] < 4 )
-                               continue;
-
-                       if ( (p1[2] & 0x80) == 0x80 ) {
-                               if ( iep < 15 ) {
-                                       pins = p2[3]; /* not pins -- actually "cables" */
-                                       if ( pins > 16 )
-                                               pins = 16;
-                                       u->in[iep].endpoint = p1[2];
-                                       u->in[iep].cableId = ( 1 << pins ) - 1;
-                                       if ( u->in[iep].cableId )
-                                               iep ++;
-                                       if ( iep < 15 ) {
-                                               u->in[iep].endpoint = -1;
-                                               u->in[iep].cableId = -1;
-                                       }
-                               }
-                       } else {
-                               if ( oep < 15 ) {
-                                       pins = p2[3]; /* not pins -- actually "cables" */
-                                       if ( pins > 16 )
-                                               pins = 16;
-                                       u->out[oep].endpoint = p1[2];
-                                       u->out[oep].cableId = ( 1 << pins ) - 1;
-                                       if ( u->out[oep].cableId )
-                                               oep ++;
-                                       if ( oep < 15 ) {
-                                               u->out[oep].endpoint = -1;
-                                               u->out[oep].cableId = -1;
-                                       }
-                               }
-                       }
-       
-               }
-       } else if (quirks==1) {
-               /* YAMAHA quirks */
-               for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
-                                         ifnum, altSetting ); p1; p1 = next ) {
-                       next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
-                                              ifnum, altSetting ); 
-       
-                       if ( p1[0] < 7 )
-                               continue;
-
-                       if ( (p1[2] & 0x80) == 0x80 ) {
-                               if ( iep < 15 ) {
-                                       pins = iep+1;
-                                       if ( pins > 16 )
-                                               pins = 16;
-                                       u->in[iep].endpoint = p1[2];
-                                       u->in[iep].cableId = ( 1 << pins ) - 1;
-                                       if ( u->in[iep].cableId )
-                                               iep ++;
-                                       if ( iep < 15 ) {
-                                               u->in[iep].endpoint = -1;
-                                               u->in[iep].cableId = -1;
-                                       }
-                               }
-                       } else {
-                               if ( oep < 15 ) {
-                                       pins = oep+1;
-                                       u->out[oep].endpoint = p1[2];
-                                       u->out[oep].cableId = ( 1 << pins ) - 1;
-                                       if ( u->out[oep].cableId )
-                                               oep ++;
-                                       if ( oep < 15 ) {
-                                               u->out[oep].endpoint = -1;
-                                               u->out[oep].cableId = -1;
-                                       }
-                               }
-                       }
-       
-               }
-       }
-
-       if ( !iep && ! oep ) {
-               goto error_end;
-       }
-
-       return u;
-
-error_end:
-       kfree(u);
-       return NULL;
-}
-
-/* ------------------------------------------------------------------------- */
-
-/** Returns number between 0 and 16.
- *
- **/
-static int on_bits( unsigned short v )
-{
-       int i;
-       int ret=0;
-
-       for ( i=0 ; i<16 ; i++ ) {
-               if ( v & (1<<i) )
-                       ret++;
-       }
-
-       return ret;
-}
-
-
-/** USB-device will be interrogated for altSetting.
- *
- * Returns negative on error.
- * Called by allocUsbMidiDev();
- *
- **/
-
-static int get_alt_setting( struct usb_device *d, int ifnum )
-{
-       int alts, alt=0;
-       struct usb_interface *iface;
-       struct usb_host_interface *interface;
-       struct usb_endpoint_descriptor *ep;
-       int epin, epout;
-       int i;
-
-       iface = usb_ifnum_to_if( d, ifnum );
-       alts = iface->num_altsetting;
-
-       for ( alt=0 ; alt<alts ; alt++ ) {
-               interface = &iface->altsetting[alt];
-               epin = -1;
-               epout = -1;
-
-               for ( i=0 ; i<interface->desc.bNumEndpoints ; i++ ) {
-                       ep = &interface->endpoint[i].desc;
-                       if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) {
-                               continue;
-                       }
-                       if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) {
-                               epin = i;
-                       } else if ( epout < 0 ) {
-                               epout = i;
-                       }
-                       if ( epin >= 0 && epout >= 0 ) {
-                               return interface->desc.bAlternateSetting;
-                       }
-               }
-       }
-
-       return -ENODEV;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-/** Returns 0 if successful in allocating and registering internal structures.
- * Returns negative on failure.
- * Calls allocMidiDev which additionally registers /dev/midiXX devices.
- * Writes messages on success to indicate which /dev/midiXX is which physical
- * endpoint.
- *
- **/
-static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u )
-{
-       struct usb_mididev **mdevs=NULL;
-       struct midi_in_endpoint *mins[15], *min;
-       struct midi_out_endpoint *mouts[15], *mout;
-       int inDevs=0, outDevs=0;
-       int inEndpoints=0, outEndpoints=0;
-       int inEndpoint, outEndpoint;
-       int inCableId, outCableId;
-       int i;
-       int devices = 0;
-       int alt = 0;
-
-       /* Obtain altSetting or die.. */
-       alt = u->altSetting;
-       if ( alt < 0 ) {
-               alt = get_alt_setting( d, u->interface );
-       }
-       if ( alt < 0 )
-               return -ENXIO;
-
-       /* Configure interface */
-       if ( usb_set_interface( d, u->interface, alt ) < 0 ) {
-               return -ENXIO;
-       }
-
-       for ( i = 0 ; i < 15 ; i++ ) {
-               mins[i] = NULL;
-               mouts[i] = NULL;
-       }
-
-       /* Begin Allocation */
-       while( inEndpoints < 15
-              && inDevs < maxdevices
-              && u->in[inEndpoints].cableId >= 0 ) {
-               inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId);
-               mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint );
-               if ( mins[inEndpoints] == NULL )
-                       goto error_end;
-               inEndpoints++;
-       }
-
-       while( outEndpoints < 15
-              && outDevs < maxdevices
-              && u->out[outEndpoints].cableId >= 0 ) {
-               outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId);
-               mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint );
-               if ( mouts[outEndpoints] == NULL )
-                       goto error_end;
-               outEndpoints++;
-       }
-
-       devices = inDevs > outDevs ? inDevs : outDevs;
-       devices = maxdevices > devices ? devices : maxdevices;
-
-       /* obtain space for device name (iProduct) if not known. */
-       if ( ! u->deviceName ) {
-               mdevs = (struct usb_mididev **)
-                       kmalloc(sizeof(struct usb_mididevs *)*devices
-                               + sizeof(char) * 256, GFP_KERNEL);
-       } else {
-               mdevs = (struct usb_mididev **)
-                       kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL);
-       }
-
-       if ( !mdevs ) {
-               /* devices = 0; */
-               /* mdevs = NULL; */
-               goto error_end;
-       }
-       for ( i=0 ; i<devices ; i++ ) {
-               mdevs[i] = NULL;
-       }
-
-       /* obtain device name (iProduct) if not known. */
-       if ( ! u->deviceName ) {
-               u->deviceName = (char *) (mdevs + devices);
-               if ( ! d->have_langid && d->descriptor.iProduct) {
-                       alt = usb_get_string(d, 0, 0, u->deviceName, 250);
-                       if (alt < 0) {
-                               printk(KERN_INFO "error getting string descriptor 0 (error=%d)\n", alt);
-                       } else if (u->deviceName[0] < 4) {
-                               printk(KERN_INFO "string descriptor 0 too short (length = %d)\n", alt);
-                       } else {
-                               printk(KERN_INFO "string descriptor 0 found (length = %d)\n", alt);
-                               for(; alt >= 4; alt -= 2) {
-                                       i = u->deviceName[alt-2] | (u->deviceName[alt-1]<< 8);
-                                       printk(KERN_INFO "usb-midi: langid(%d) 0x%04x\n",
-                                              (alt-4) >> 1, i);
-                                       if ( ( ( i ^ ulangid ) & 0xff ) == 0 ) {
-                                               d->have_langid = 1;
-                                               d->string_langid = i;
-                                               printk(KERN_INFO "usb-midi: langid(match) 0x%04x\n", i);
-                                               if ( i == ulangid )
-                                                       break;
-                                       }
-                               }
-                       }
-               }
-               u->deviceName[0] = (char) 0;
-               if (d->descriptor.iProduct) {
-                       printk(KERN_INFO "usb-midi: fetchString(%d)\n", d->descriptor.iProduct);
-                       alt = usb_string(d, d->descriptor.iProduct, u->deviceName, 255);
-                       if( alt < 0 ) {
-                               u->deviceName[0] = (char) 0;
-                       }
-                       printk(KERN_INFO "usb-midi: fetchString = %d\n", alt);
-               } 
-               /* Failsafe */
-               if ( !u->deviceName[0] ) {
-                       if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_ROLAND ) {
-                               strcpy(u->deviceName, "Unknown Roland");
-                       } else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_STEINBERG  ) {
-                               strcpy(u->deviceName, "Unknown Steinberg");
-                       } else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_YAMAHA ) {
-                               strcpy(u->deviceName, "Unknown Yamaha");
-                       } else {
-                               strcpy(u->deviceName, "Unknown");
-                       }
-               }
-       }
-
-       inEndpoint  = 0; inCableId  = -1;
-       outEndpoint = 0; outCableId = -1;
-
-       for ( i=0 ; i<devices ; i++ ) {
-               for ( inCableId ++ ;
-                     inEndpoint <15
-                             && mins[inEndpoint] 
-                             && !(u->in[inEndpoint].cableId & (1<<inCableId)) ;
-                     inCableId++ ) {
-                       if ( inCableId >= 16 ) {
-                               inEndpoint  ++;
-                               inCableId  = 0;
-                       }
-               }
-               min  = mins[inEndpoint];
-               for ( outCableId ++ ;
-                     outEndpoint <15
-                             && mouts[outEndpoint] 
-                             && !(u->out[outEndpoint].cableId & (1<<outCableId)) ;
-                     outCableId++ ) {
-                       if ( outCableId >= 16 ) {
-                               outEndpoint  ++;
-                               outCableId  = 0;
-                       }
-               }
-               mout = mouts[outEndpoint];
-
-               mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId );
-               if ( mdevs[i] == NULL )
-                       goto error_end;
-
-       }
-
-       /* Success! */
-       for ( i=0 ; i<devices ; i++ ) {
-               list_add_tail( &mdevs[i]->list, &s->midiDevList );
-       }
-       for ( i=0 ; i<inEndpoints ; i++ ) {
-               list_add_tail( &mins[i]->list, &s->inEndpointList );
-       }
-       for ( i=0 ; i<outEndpoints ; i++ ) {
-               list_add_tail( &mouts[i]->list, &s->outEndpointList );
-       }
-
-       printk(KERN_INFO "usbmidi: found [ %s ] (0x%04x:0x%04x), attached:\n", u->deviceName, u->idVendor, u->idProduct );
-       for ( i=0 ; i<devices ; i++ ) {
-               int dm = (mdevs[i]->dev_midi-2)>>4;
-               if ( mdevs[i]->mout.ep != NULL && mdevs[i]->min.ep != NULL ) {
-                       printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%2d) out (ep:%02x cid:%2d bufsiz:%2d)\n", 
-                              dm,
-                              mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize,
-                              mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
-               } else if ( mdevs[i]->min.ep != NULL ) {
-                       printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%02d)\n", 
-                              dm,
-                              mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize);
-               } else if ( mdevs[i]->mout.ep != NULL ) {
-                       printk(KERN_INFO "usbmidi: /dev/midi%02d: out (ep:%02x cid:%2d bufsiz:%02d)\n", 
-                              dm,
-                              mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
-               }
-       }
-
-       kfree(mdevs);
-       return 0;
-
- error_end:
-       if ( mdevs != NULL ) {
-               for ( i=0 ; i<devices ; i++ ) {
-                       if ( mdevs[i] != NULL ) {
-                               unregister_sound_midi( mdevs[i]->dev_midi );
-                               kfree(mdevs[i]);
-                       }
-               }
-               kfree(mdevs);
-       }
-
-       for ( i=0 ; i<15 ; i++ ) {
-               if ( mins[i] != NULL ) {
-                       remove_midi_in_endpoint( mins[i] );
-               }
-               if ( mouts[i] != NULL ) {
-                       remove_midi_out_endpoint( mouts[i] );
-               }
-       }
-
-       return -ENOMEM;
-}
-
-/* ------------------------------------------------------------------------- */
-
-/** Attempt to scan YAMAHA's device descriptor and detect correct values of
- *  them.
- *  Return 0 on succes, negative on failure.
- *  Called by usb_midi_probe();
- **/
-
-static int detect_yamaha_device( struct usb_device *d,
-               struct usb_interface *iface, unsigned int ifnum,
-               struct usb_midi_state *s)
-{
-       struct usb_host_interface *interface;
-       struct usb_midi_device *u;
-       unsigned char *buffer;
-       int bufSize;
-       int i;
-       int alts=-1;
-       int ret;
-
-       if (le16_to_cpu(d->descriptor.idVendor) != USB_VENDOR_ID_YAMAHA) {
-               return -EINVAL;
-       }
-
-       for ( i=0 ; i < iface->num_altsetting; i++ ) {
-               interface = iface->altsetting + i;
-
-               if ( interface->desc.bInterfaceClass != 255 ||
-                    interface->desc.bInterfaceSubClass != 0 )
-                       continue;
-               alts = interface->desc.bAlternateSetting;
-       }
-       if ( alts == -1 ) {
-               return -EINVAL;
-       }
-
-       printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
-              le16_to_cpu(d->descriptor.idVendor),
-              le16_to_cpu(d->descriptor.idProduct), ifnum);
-
-       i = d->actconfig - d->config;
-       buffer = d->rawdescriptors[i];
-       bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength);
-
-       u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
-       if ( u == NULL ) {
-               return -EINVAL;
-       }
-
-       ret = alloc_usb_midi_device( d, s, u );
-
-       kfree(u);
-
-       return ret;
-}
-
-
-/** Scan table of known devices which are only partially compliant with 
- * the MIDIStreaming specification.
- * Called by usb_midi_probe();
- *
- **/
-
-static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s )
-{
-       struct usb_midi_device *u;
-       int i;
-       int ret = -ENXIO;
-
-       for ( i=0; i<VENDOR_SPECIFIC_USB_MIDI_DEVICES ; i++ ) {
-               u=&(usb_midi_devices[i]);
-    
-               if ( le16_to_cpu(d->descriptor.idVendor) != u->idVendor ||
-                    le16_to_cpu(d->descriptor.idProduct) != u->idProduct ||
-                    ifnum != u->interface )
-                       continue;
-
-               ret = alloc_usb_midi_device( d, s, u );
-               break;
-       }
-
-       return ret;
-}
-
-
-/** Attempt to match any config of an interface to a MIDISTREAMING interface.
- *  Returns 0 on success, negative on failure.
- * Called by usb_midi_probe();
- **/
-static int detect_midi_subclass(struct usb_device *d,
-               struct usb_interface *iface, unsigned int ifnum,
-               struct usb_midi_state *s)
-{
-       struct usb_host_interface *interface;
-       struct usb_midi_device *u;
-       unsigned char *buffer;
-       int bufSize;
-       int i;
-       int alts=-1;
-       int ret;
-
-       for ( i=0 ; i < iface->num_altsetting; i++ ) {
-               interface = iface->altsetting + i;
-
-               if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO ||
-                    interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
-                       continue;
-               alts = interface->desc.bAlternateSetting;
-       }
-       if ( alts == -1 ) {
-               return -EINVAL;
-       }
-
-       printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n",
-              le16_to_cpu(d->descriptor.idVendor), 
-              le16_to_cpu(d->descriptor.idProduct), ifnum);
-
-
-       /* From USB Spec v2.0, Section 9.5.
-          If the class or vendor specific descriptors use the same format
-          as standard descriptors (e.g., start with a length byte and
-          followed by a type byte), they must be returned interleaved with
-          standard descriptors in the configuration information returned by
-          a GetDescriptor(Configuration) request. In this case, the class
-          or vendor-specific descriptors must follow a related standard
-          descriptor they modify or extend.
-       */
-
-       i = d->actconfig - d->config;
-       buffer = d->rawdescriptors[i];
-       bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength);
-
-       u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
-       if ( u == NULL ) {
-               return -EINVAL;
-       }
-
-       ret = alloc_usb_midi_device( d, s, u );
-
-       kfree(u);
-
-       return ret;
-}
-
-
-/** When user has requested a specific device, match it exactly.
- *
- * Uses uvendor, uproduct, uinterface, ualt, umin, umout and ucable.
- * Called by usb_midi_probe();
- *
- **/
-static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
-{
-       struct usb_midi_device u;
-
-       if ( le16_to_cpu(d->descriptor.idVendor) != uvendor ||
-            le16_to_cpu(d->descriptor.idProduct) != uproduct ||
-            ifnum != uinterface ) {
-               return -EINVAL;
-       }
-
-       if ( ualt < 0 )
-               ualt = -1;
-
-       if ( umin   < 0 || umin   > 15 )
-               umin   = 0x01 | USB_DIR_IN;
-       if ( umout  < 0 || umout  > 15 )
-               umout  = 0x01;
-       if ( ucable < 0 || ucable > 15 )
-               ucable = 0;
-
-       u.deviceName = NULL; /* A flag for alloc_usb_midi_device to get device
-                               name from device. */
-       u.idVendor   = uvendor;
-       u.idProduct  = uproduct;
-       u.interface  = uinterface;
-       u.altSetting = ualt;
-
-       u.in[0].endpoint    = umin;
-       u.in[0].cableId     = (1<<ucable);
-
-       u.out[0].endpoint   = umout;
-       u.out[0].cableId    = (1<<ucable);
-
-       return alloc_usb_midi_device( d, s, &u );
-}
-
-
-
-/* ------------------------------------------------------------------------- */
-
-static int usb_midi_probe(struct usb_interface *intf, 
-                         const struct usb_device_id *id)
-{
-       struct usb_midi_state *s;
-       struct usb_device *dev = interface_to_usbdev(intf);
-       int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
-       s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
-       if ( !s )
-               return -ENOMEM;
-
-       memset( s, 0, sizeof(struct usb_midi_state) );
-       INIT_LIST_HEAD(&s->midiDevList);
-       INIT_LIST_HEAD(&s->inEndpointList);
-       INIT_LIST_HEAD(&s->outEndpointList);
-       s->usbdev = dev;
-       s->count  = 0;
-       spin_lock_init(&s->lock);
-
-       if (
-               detect_by_hand( dev, ifnum, s ) &&
-               detect_midi_subclass( dev, intf, ifnum, s ) &&
-               detect_vendor_specific_device( dev, ifnum, s ) &&
-               detect_yamaha_device( dev, intf, ifnum, s) ) {
-               kfree(s);
-               return -EIO;
-       }
-
-       down(&open_sem);
-       list_add_tail(&s->mididev, &mididevs);
-       up(&open_sem);
-
-       usb_set_intfdata (intf, s);
-       return 0;
-}
-
-
-static void usb_midi_disconnect(struct usb_interface *intf)
-{
-       struct usb_midi_state *s = usb_get_intfdata (intf);
-       struct usb_mididev    *m;
-
-       if ( !s )
-               return;
-
-       if ( s == (struct usb_midi_state *)-1 ) {
-               return;
-       }
-       if ( !s->usbdev ) {
-               return;
-       }
-       down(&open_sem);
-       list_del(&s->mididev);
-       INIT_LIST_HEAD(&s->mididev);
-       s->usbdev = NULL;
-       usb_set_intfdata (intf, NULL);
-
-       list_for_each_entry(m, &s->midiDevList, list) {
-               wake_up(&(m->min.ep->wait));
-               wake_up(&(m->mout.ep->wait));
-               if ( m->dev_midi >= 0 ) {
-                       unregister_sound_midi(m->dev_midi);
-               }
-               m->dev_midi = -1;
-       }
-       release_midi_device(s);
-       wake_up(&open_wait);
-}
-
-/* we want to look at all devices by hand */
-static struct usb_device_id id_table[] = {
-       {.driver_info = 42},
-       {}
-};
-
-static struct usb_driver usb_midi_driver = {
-       .name =         "midi",
-       .probe =        usb_midi_probe,
-       .disconnect =   usb_midi_disconnect,
-       .id_table =     id_table,
-};
-
-/* ------------------------------------------------------------------------- */
-
-static int __init usb_midi_init(void)
-{
-       return usb_register(&usb_midi_driver);
-}
-
-static void __exit usb_midi_exit(void)
-{
-       usb_deregister(&usb_midi_driver);
-}
-
-module_init(usb_midi_init) ;
-module_exit(usb_midi_exit) ;
-
-#ifdef HAVE_ALSA_SUPPORT
-#define SNDRV_MAIN_OBJECT_FILE
-#include "../../include/driver.h"
-#include "../../include/control.h"
-#include "../../include/info.h"
-#include "../../include/cs46xx.h"
-
-/* ------------------------------------------------------------------------- */
-
-static int snd_usbmidi_input_close(snd_rawmidi_substream_t * substream)
-{
-       return 0;
-}
-
-static int snd_usbmidi_input_open(snd_rawmidi_substream_t * substream )
-{
-       return 0;
-}
-
-static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
-{
-       return 0;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-static int snd_usbmidi_output_close(snd_rawmidi_substream_t * substream)
-{
-       return 0;
-}
-
-static int snd_usbmidi_output_open(snd_rawmidi_substream_t * substream)
-{
-       return 0;
-}
-
-static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream,
-                                       int up)
-{
-       return 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static snd_rawmidi_ops_t snd_usbmidi_output =
-{
-        .open =         snd_usbmidi_output_open,
-        .close =        snd_usbmidi_output_close,
-        .trigger =      snd_usbmidi_output_trigger,
-};
-static snd_rawmidi_ops_t snd_usbmidi_input =
-{
-        .open =         snd_usbmidi_input_open,
-        .close =        snd_usbmidi_input_close,
-        .trigger =      snd_usbmidi_input_trigger,
-};
-
-int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi)
-{
-       snd_rawmidi_t *rmidi;
-       int err;
-
-       if (rrawmidi)
-               *rrawmidi = NULL;
-       if ((err = snd_rawmidi_new(chip->card, "USB-MIDI", device, 1, 1, &rmidi)) < 0)
-               return err;
-       strcpy(rmidi->name, "USB-MIDI");
-
-       snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output );
-       snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input );
-
-       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
-
-       rmidi->private_data = chip;
-       chip->rmidi = rmidi;
-       if (rrawmidi)
-               *rrawmidi = NULL;
-
-       return 0;
-}
-
-int snd_usbmidi_create( snd_card_t * card,
-                       struct pci_dev * pci,
-                       usbmidi_t ** rchip )
-{
-       usbmidi_t *chip;
-       int err, idx;
-       snd_region_t *region;
-       static snd_device_opt_t ops = {
-               .dev_free = snd_usbmidi_dev_free,
-       };
-
-       *rchip = NULL;
-       chip = snd_magic_kcalloc( usbmidi_t, 0, GFP_KERNEL );
-       if ( chip == NULL )
-               return -ENOMEM;
-}
-
-EXPORT_SYMBOL(snd_usbmidi_create);
-EXPORT_SYMBOL(snd_usbmidi_midi);
-#endif /* HAVE_ALSA_SUPPORT */
-
diff --git a/drivers/usb/class/usb-midi.h b/drivers/usb/class/usb-midi.h
deleted file mode 100644 (file)
index 358cdef..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
-  usb-midi.h  --  USB-MIDI driver
-
-  Copyright (C) 2001
-      NAGANO Daisuke <breeze.nagano@nifty.ne.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
-  the Free Software Foundation; either version 2, or (at your option)
-  any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* ------------------------------------------------------------------------- */
-
-#ifndef _USB_MIDI_H_
-#define _USB_MIDI_H_
-
-#ifndef USB_SUBCLASS_MIDISTREAMING
-#define USB_SUBCLASS_MIDISTREAMING     3
-#endif
-
-/* ------------------------------------------------------------------------- */
-/* Roland MIDI Devices */
-
-#define USB_VENDOR_ID_ROLAND           0x0582
-#define USBMIDI_ROLAND_UA100G          0x0000
-#define USBMIDI_ROLAND_MPU64           0x0002
-#define USBMIDI_ROLAND_SC8850          0x0003
-#define USBMIDI_ROLAND_SC8820          0x0007
-#define USBMIDI_ROLAND_UM2             0x0005
-#define USBMIDI_ROLAND_UM1             0x0009
-#define USBMIDI_ROLAND_PC300           0x0008
-
-/* YAMAHA MIDI Devices */
-#define USB_VENDOR_ID_YAMAHA           0x0499
-#define USBMIDI_YAMAHA_MU1000          0x1001
-
-/* Steinberg MIDI Devices */
-#define USB_VENDOR_ID_STEINBERG                0x0763
-#define USBMIDI_STEINBERG_USB2MIDI     0x1001
-
-/* Mark of the Unicorn MIDI Devices */
-#define USB_VENDOR_ID_MOTU             0x07fd
-#define USBMIDI_MOTU_FASTLANE          0x0001
-
-/* ------------------------------------------------------------------------- */
-/* Supported devices */
-
-struct usb_midi_endpoint {
-       int  endpoint;
-       int  cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */
-};
-
-struct usb_midi_device {
-       char  *deviceName;
-
-       u16    idVendor;
-       u16    idProduct;
-       int    interface;
-       int    altSetting; /* -1: auto detect */
-
-       struct usb_midi_endpoint in[15];
-       struct usb_midi_endpoint out[15];
-};
-
-static struct usb_midi_device usb_midi_devices[] = {
-  { /* Roland UM-1 */
-    "Roland UM-1",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1,
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 1,}, {-1, -1} },
-  },
-
-  { /* Roland UM-2 */
-    "Roland UM-2" ,
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1,
-    { { 0x81, 3 }, {-1, -1} },
-    { { 0x01, 3,}, {-1, -1} },
-  },
-
-/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
-  { /* Roland UA-100 */
-    "Roland UA-100",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1,
-    { { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/
-    { { 0x02, 7 }, {-1, -1} },
-  },
-
-/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
-  { /* Roland SC8850 */
-    "Roland SC8850",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
-    { { 0x81, 0x3f }, {-1, -1} },
-    { { 0x01, 0x3f }, {-1, -1} },
-  },
-
-  { /* Roland SC8820 */
-    "Roland SC8820",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
-    { { 0x81, 0x13 }, {-1, -1} },
-    { { 0x01, 0x13 }, {-1, -1} },
-  },
-
-  { /* Roland SC8820 */
-    "Roland SC8820",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
-    { { 0x81, 17 }, {-1, -1} },
-    { { 0x01, 17 }, {-1, -1} },
-  },
-
-  { /* YAMAHA MU1000 */
-    "YAMAHA MU1000",
-    USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, 
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 15 }, {-1, -1} },
-  },
-  { /* Roland PC-300 */
-    "Roland PC-300",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, 
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 1 }, {-1, -1} },
-  },
-  { /* MOTU Fastlane USB */
-    "MOTU Fastlane USB",
-    USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE, 1, 0,
-    { { 0x82, 3 }, {-1, -1} },
-    { { 0x02, 3 }, {-1, -1} },
-  }
-};
-
-#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device))
-
-/* for Hot-Plugging */
-
-static struct usb_device_id usb_midi_ids [] = {
-       { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
-         .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING},
-       { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1    ) },
-       { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2    ) },
-       { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
-       { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
-       { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
-       { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820 ) },
-       { USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
-       { USB_DEVICE( USB_VENDOR_ID_MOTU,   USBMIDI_MOTU_FASTLANE ) },
-/*     { USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
-       { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_midi_ids);
-
-/* ------------------------------------------------------------------------- */
-#endif /* _USB_MIDI_H_ */
-
-
index d34848a..48dee4b 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/lp.h>
+#include <linux/mutex.h>
 #undef DEBUG
 #include <linux/usb.h>
 
@@ -223,7 +224,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp);
 
 /* forward reference to make our lives easier */
 static struct usb_driver usblp_driver;
-static DECLARE_MUTEX(usblp_sem);       /* locks the existence of usblp's */
+static DEFINE_MUTEX(usblp_mutex);      /* locks the existence of usblp's */
 
 /*
  * Functions for usblp control messages.
@@ -351,7 +352,7 @@ static int usblp_open(struct inode *inode, struct file *file)
        if (minor < 0)
                return -ENODEV;
 
-       down (&usblp_sem);
+       mutex_lock (&usblp_mutex);
 
        retval = -ENODEV;
        intf = usb_find_interface(&usblp_driver, minor);
@@ -399,7 +400,7 @@ static int usblp_open(struct inode *inode, struct file *file)
                }
        }
 out:
-       up (&usblp_sem);
+       mutex_unlock (&usblp_mutex);
        return retval;
 }
 
@@ -425,13 +426,13 @@ static int usblp_release(struct inode *inode, struct file *file)
 {
        struct usblp *usblp = file->private_data;
 
-       down (&usblp_sem);
+       mutex_lock (&usblp_mutex);
        usblp->used = 0;
        if (usblp->present) {
                usblp_unlink_urbs(usblp);
        } else          /* finish cleanup from disconnect */
                usblp_cleanup (usblp);
-       up (&usblp_sem);
+       mutex_unlock (&usblp_mutex);
        return 0;
 }
 
@@ -1152,7 +1153,7 @@ static void usblp_disconnect(struct usb_interface *intf)
 
        device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
 
-       down (&usblp_sem);
+       mutex_lock (&usblp_mutex);
        down (&usblp->sem);
        usblp->present = 0;
        usb_set_intfdata (intf, NULL);
@@ -1166,7 +1167,7 @@ static void usblp_disconnect(struct usb_interface *intf)
 
        if (!usblp->used)
                usblp_cleanup (usblp);
-       up (&usblp_sem);
+       mutex_unlock (&usblp_mutex);
 }
 
 static struct usb_device_id usblp_ids [] = {
index 2684e15..c0f3734 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "usb.h"
@@ -570,7 +571,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
        if (!access_ok(VERIFY_WRITE, buf, nbytes))
                return -EFAULT;
 
-       down (&usb_bus_list_lock);
+       mutex_lock(&usb_bus_list_lock);
        /* print devices for all busses */
        list_for_each_entry(bus, &usb_bus_list, bus_list) {
                /* recurse through all children of the root hub */
@@ -580,12 +581,12 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
                ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
                usb_unlock_device(bus->root_hub);
                if (ret < 0) {
-                       up(&usb_bus_list_lock);
+                       mutex_unlock(&usb_bus_list_lock);
                        return ret;
                }
                total_written += ret;
        }
-       up (&usb_bus_list_lock);
+       mutex_unlock(&usb_bus_list_lock);
        return total_written;
 }
 
index 2b68998..545da37 100644 (file)
@@ -134,26 +134,21 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
        }
 
        if (pos < sizeof(struct usb_device_descriptor)) {
-               struct usb_device_descriptor *desc = kmalloc(sizeof(*desc), GFP_KERNEL);
-               if (!desc) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               memcpy(desc, &dev->descriptor, sizeof(dev->descriptor));
-               le16_to_cpus(&desc->bcdUSB);
-               le16_to_cpus(&desc->idVendor);
-               le16_to_cpus(&desc->idProduct);
-               le16_to_cpus(&desc->bcdDevice);
+               struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
+
+               memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
+               le16_to_cpus(&temp_desc.bcdUSB);
+               le16_to_cpus(&temp_desc.idVendor);
+               le16_to_cpus(&temp_desc.idProduct);
+               le16_to_cpus(&temp_desc.bcdDevice);
 
                len = sizeof(struct usb_device_descriptor) - pos;
                if (len > nbytes)
                        len = nbytes;
-               if (copy_to_user(buf, ((char *)desc) + pos, len)) {
-                       kfree(desc);
+               if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
                        ret = -EFAULT;
                        goto err;
                }
-               kfree(desc);
 
                *ppos += len;
                buf += len;
@@ -498,7 +493,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
 {
        int ret = 0;
 
-       if (ps->dev->state != USB_STATE_CONFIGURED)
+       if (ps->dev->state != USB_STATE_ADDRESS
+        && ps->dev->state != USB_STATE_CONFIGURED)
                return -EHOSTUNREACH;
        if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
                return 0;
index dce9d98..c196f38 100644 (file)
@@ -378,7 +378,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
 
        return NULL;
 }
-EXPORT_SYMBOL(usb_match_id);
+EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
 
 int usb_device_match(struct device *dev, struct device_driver *drv)
 {
@@ -446,7 +446,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
 
        return retval;
 }
-EXPORT_SYMBOL(usb_register_driver);
+EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
 
 /**
  * usb_deregister - unregister a USB driver
@@ -469,4 +469,4 @@ void usb_deregister(struct usb_driver *driver)
 
        usbfs_update_special();
 }
-EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
index 29b5b2a..e0afb5a 100644 (file)
@@ -264,14 +264,19 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
                 */
                retval = pci_set_power_state (dev, PCI_D3hot);
                if (retval == 0) {
-                       dev_dbg (hcd->self.controller, "--> PCI D3\n");
+                       int wake = device_can_wakeup(&hcd->self.root_hub->dev);
+
+                       wake = wake && device_may_wakeup(hcd->self.controller);
+
+                       dev_dbg (hcd->self.controller, "--> PCI D3%s\n",
+                                       wake ? "/wakeup" : "");
 
                        /* Ignore these return values.  We rely on pci code to
                         * reject requests the hardware can't implement, rather
                         * than coding the same thing.
                         */
-                       (void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
-                       (void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
+                       (void) pci_enable_wake (dev, PCI_D3hot, wake);
+                       (void) pci_enable_wake (dev, PCI_D3cold, wake);
                } else {
                        dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
                                        retval);
index 0018bbc..fbd938d 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/scatterlist.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 
@@ -93,7 +94,7 @@ struct usb_busmap {
 static struct usb_busmap busmap;
 
 /* used when updating list of hcds */
-DECLARE_MUTEX (usb_bus_list_lock);     /* exported only for usbfs */
+DEFINE_MUTEX(usb_bus_list_lock);       /* exported only for usbfs */
 EXPORT_SYMBOL_GPL (usb_bus_list_lock);
 
 /* used for controlling access to virtual root hubs */
@@ -366,21 +367,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 
        /* DEVICE REQUESTS */
 
+       /* The root hub's remote wakeup enable bit is implemented using
+        * driver model wakeup flags.  If this system supports wakeup
+        * through USB, userspace may change the default "allow wakeup"
+        * policy through sysfs or these calls.
+        *
+        * Most root hubs support wakeup from downstream devices, for
+        * runtime power management (disabling USB clocks and reducing
+        * VBUS power usage).  However, not all of them do so; silicon,
+        * board, and BIOS bugs here are not uncommon, so these can't
+        * be treated quite like external hubs.
+        *
+        * Likewise, not all root hubs will pass wakeup events upstream,
+        * to wake up the whole system.  So don't assume root hub and
+        * controller capabilities are identical.
+        */
+
        case DeviceRequest | USB_REQ_GET_STATUS:
-               tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
+               tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)
+                                       << USB_DEVICE_REMOTE_WAKEUP)
                                | (1 << USB_DEVICE_SELF_POWERED);
                tbuf [1] = 0;
                len = 2;
                break;
        case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
                if (wValue == USB_DEVICE_REMOTE_WAKEUP)
-                       hcd->remote_wakeup = 0;
+                       device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);
                else
                        goto error;
                break;
        case DeviceOutRequest | USB_REQ_SET_FEATURE:
-               if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)
-                       hcd->remote_wakeup = 1;
+               if (device_can_wakeup(&hcd->self.root_hub->dev)
+                               && wValue == USB_DEVICE_REMOTE_WAKEUP)
+                       device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);
                else
                        goto error;
                break;
@@ -409,7 +428,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
                                bufp = fs_rh_config_descriptor;
                                len = sizeof fs_rh_config_descriptor;
                        }
-                       if (hcd->can_wakeup)
+                       if (device_can_wakeup(&hcd->self.root_hub->dev))
                                patch_wakeup = 1;
                        break;
                case USB_DT_STRING << 8:
@@ -761,14 +780,14 @@ static int usb_register_bus(struct usb_bus *bus)
 {
        int busnum;
 
-       down (&usb_bus_list_lock);
+       mutex_lock(&usb_bus_list_lock);
        busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
        if (busnum < USB_MAXBUS) {
                set_bit (busnum, busmap.busmap);
                bus->busnum = busnum;
        } else {
                printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-               up(&usb_bus_list_lock);
+               mutex_unlock(&usb_bus_list_lock);
                return -E2BIG;
        }
 
@@ -776,7 +795,7 @@ static int usb_register_bus(struct usb_bus *bus)
                                             bus->controller, "usb_host%d", busnum);
        if (IS_ERR(bus->class_dev)) {
                clear_bit(busnum, busmap.busmap);
-               up(&usb_bus_list_lock);
+               mutex_unlock(&usb_bus_list_lock);
                return PTR_ERR(bus->class_dev);
        }
 
@@ -784,7 +803,7 @@ static int usb_register_bus(struct usb_bus *bus)
 
        /* Add it to the local list of buses */
        list_add (&bus->bus_list, &usb_bus_list);
-       up (&usb_bus_list_lock);
+       mutex_unlock(&usb_bus_list_lock);
 
        usb_notify_add_bus(bus);
 
@@ -809,9 +828,9 @@ static void usb_deregister_bus (struct usb_bus *bus)
         * controller code, as well as having it call this when cleaning
         * itself up
         */
-       down (&usb_bus_list_lock);
+       mutex_lock(&usb_bus_list_lock);
        list_del (&bus->bus_list);
-       up (&usb_bus_list_lock);
+       mutex_unlock(&usb_bus_list_lock);
 
        usb_notify_remove_bus(bus);
 
@@ -822,18 +841,17 @@ static void usb_deregister_bus (struct usb_bus *bus)
 
 /**
  * register_root_hub - called by usb_add_hcd() to register a root hub
- * @usb_dev: the usb root hub device to be registered.
  * @hcd: host controller for this root hub
  *
  * This function registers the root hub with the USB subsystem.  It sets up
- * the device properly in the device tree and stores the root_hub pointer
- * in the bus structure, then calls usb_new_device() to register the usb
- * device.  It also assigns the root hub's USB address (always 1).
+ * the device properly in the device tree and then calls usb_new_device()
+ * to register the usb device.  It also assigns the root hub's USB address
+ * (always 1).
  */
-static int register_root_hub (struct usb_device *usb_dev,
-               struct usb_hcd *hcd)
+static int register_root_hub(struct usb_hcd *hcd)
 {
        struct device *parent_dev = hcd->self.controller;
+       struct usb_device *usb_dev = hcd->self.root_hub;
        const int devnum = 1;
        int retval;
 
@@ -844,14 +862,12 @@ static int register_root_hub (struct usb_device *usb_dev,
        set_bit (devnum, usb_dev->bus->devmap.devicemap);
        usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
 
-       down (&usb_bus_list_lock);
-       usb_dev->bus->root_hub = usb_dev;
+       mutex_lock(&usb_bus_list_lock);
 
        usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
        retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
        if (retval != sizeof usb_dev->descriptor) {
-               usb_dev->bus->root_hub = NULL;
-               up (&usb_bus_list_lock);
+               mutex_unlock(&usb_bus_list_lock);
                dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
                                usb_dev->dev.bus_id, retval);
                return (retval < 0) ? retval : -EMSGSIZE;
@@ -859,11 +875,10 @@ static int register_root_hub (struct usb_device *usb_dev,
 
        retval = usb_new_device (usb_dev);
        if (retval) {
-               usb_dev->bus->root_hub = NULL;
                dev_err (parent_dev, "can't register root hub for %s, %d\n",
                                usb_dev->dev.bus_id, retval);
        }
-       up (&usb_bus_list_lock);
+       mutex_unlock(&usb_bus_list_lock);
 
        if (retval == 0) {
                spin_lock_irq (&hcd_root_hub_lock);
@@ -1090,7 +1105,6 @@ static void urb_unlink (struct urb *urb)
        spin_lock_irqsave (&hcd_data_lock, flags);
        list_del_init (&urb->urb_list);
        spin_unlock_irqrestore (&hcd_data_lock, flags);
-       usb_put_dev (urb->dev);
 }
 
 
@@ -1130,7 +1144,6 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
        case HC_STATE_RUNNING:
        case HC_STATE_RESUMING:
 doit:
-               usb_get_dev (urb->dev);
                list_add_tail (&urb->urb_list, &ep->urb_list);
                status = 0;
                break;
@@ -1771,12 +1784,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
-       /* till now HC has been in an indeterminate state ... */
-       if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
-               dev_err(hcd->self.controller, "can't reset\n");
-               return retval;
-       }
-
+       /* HC is in reset state, but accessible.  Now do the one-time init,
+        * bottom up so that hcds can customize the root hubs before khubd
+        * starts talking to them.  (Note, bus id is assigned early too.)
+        */
        if ((retval = hcd_buffer_create(hcd)) != 0) {
                dev_dbg(hcd->self.controller, "pool alloc failed\n");
                return retval;
@@ -1785,6 +1796,36 @@ int usb_add_hcd(struct usb_hcd *hcd,
        if ((retval = usb_register_bus(&hcd->self)) < 0)
                goto err_register_bus;
 
+       if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
+               dev_err(hcd->self.controller, "unable to allocate root hub\n");
+               retval = -ENOMEM;
+               goto err_allocate_root_hub;
+       }
+       rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
+                       USB_SPEED_FULL;
+       hcd->self.root_hub = rhdev;
+
+       /* "reset" is misnamed; its role is now one-time init. the controller
+        * should already have been reset (and boot firmware kicked off etc).
+        */
+       if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
+               dev_err(hcd->self.controller, "can't setup\n");
+               goto err_hcd_driver_setup;
+       }
+
+       /* wakeup flag init is in transition; for now we can't rely on PCI to
+        * initialize these bits properly, so we let reset() override it.
+        * This init should _precede_ the reset() once PCI behaves.
+        */
+       device_init_wakeup(&rhdev->dev,
+                       device_can_wakeup(hcd->self.controller));
+
+       /* NOTE: root hub and controller capabilities may not be the same */
+       if (device_can_wakeup(hcd->self.controller)
+                       && device_can_wakeup(&hcd->self.root_hub->dev))
+               dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+
+       /* enable irqs just before we start the controller */
        if (hcd->driver->irq) {
                char    buf[8], *bufp = buf;
 
@@ -1816,56 +1857,32 @@ int usb_add_hcd(struct usb_hcd *hcd,
                                        (unsigned long long)hcd->rsrc_start);
        }
 
-       /* Allocate the root hub before calling hcd->driver->start(),
-        * but don't register it until afterward so that the hardware
-        * is running.
-        */
-       if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
-               dev_err(hcd->self.controller, "unable to allocate root hub\n");
-               retval = -ENOMEM;
-               goto err_allocate_root_hub;
-       }
-
-       /* Although in principle hcd->driver->start() might need to use rhdev,
-        * none of the current drivers do.
-        */
        if ((retval = hcd->driver->start(hcd)) < 0) {
                dev_err(hcd->self.controller, "startup error %d\n", retval);
                goto err_hcd_driver_start;
        }
 
-       /* hcd->driver->start() reported can_wakeup, probably with
-        * assistance from board's boot firmware.
-        * NOTE:  normal devices won't enable wakeup by default.
-        */
-       if (hcd->can_wakeup)
-               dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
-       hcd->remote_wakeup = hcd->can_wakeup;
-
-       rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
-                       USB_SPEED_FULL;
+       /* starting here, usbcore will pay attention to this root hub */
        rhdev->bus_mA = min(500u, hcd->power_budget);
-       if ((retval = register_root_hub(rhdev, hcd)) != 0)
+       if ((retval = register_root_hub(hcd)) != 0)
                goto err_register_root_hub;
 
        if (hcd->uses_new_polling && hcd->poll_rh)
                usb_hcd_poll_rh_status(hcd);
        return retval;
 
- err_register_root_hub:
+err_register_root_hub:
        hcd->driver->stop(hcd);
-
- err_hcd_driver_start:
-       usb_put_dev(rhdev);
-
- err_allocate_root_hub:
+err_hcd_driver_start:
        if (hcd->irq >= 0)
                free_irq(irqnum, hcd);
-
- err_request_irq:
+err_request_irq:
+err_hcd_driver_setup:
+       hcd->self.root_hub = NULL;
+       usb_put_dev(rhdev);
+err_allocate_root_hub:
        usb_deregister_bus(&hcd->self);
-
- err_register_bus:
+err_register_bus:
        hcd_buffer_destroy(hcd);
        return retval;
 } 
@@ -1891,9 +1908,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        hcd->rh_registered = 0;
        spin_unlock_irq (&hcd_root_hub_lock);
 
-       down(&usb_bus_list_lock);
+       mutex_lock(&usb_bus_list_lock);
        usb_disconnect(&hcd->self.root_hub);
-       up(&usb_bus_list_lock);
+       mutex_unlock(&usb_bus_list_lock);
 
        hcd->poll_rh = 0;
        del_timer_sync(&hcd->rh_timer);
index 591b5aa..7022aaf 100644 (file)
@@ -78,8 +78,6 @@ struct usb_hcd {      /* usb_bus.hcpriv points to this */
 #define HCD_FLAG_HW_ACCESSIBLE 0x00000001
 #define HCD_FLAG_SAW_IRQ       0x00000002
 
-       unsigned                can_wakeup:1;   /* hw supports wakeup? */
-       unsigned                remote_wakeup:1;/* sw should use wakeup? */
        unsigned                rh_registered:1;/* is root hub registered? */
 
        /* The next flag is a stopgap, to be removed when all the HCDs
@@ -364,7 +362,7 @@ extern void usb_set_device_state(struct usb_device *udev,
 /* exported only within usbcore */
 
 extern struct list_head usb_bus_list;
-extern struct semaphore usb_bus_list_lock;
+extern struct mutex usb_bus_list_lock;
 extern wait_queue_head_t usb_kill_urb_queue;
 
 extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
index 650d5ee..8e65f7a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/kthread.h>
+#include <linux/mutex.h>
 
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -1005,12 +1006,18 @@ void usb_set_device_state(struct usb_device *udev,
                ;       /* do nothing */
        else if (new_state != USB_STATE_NOTATTACHED) {
                udev->state = new_state;
-               if (new_state == USB_STATE_CONFIGURED)
-                       device_init_wakeup(&udev->dev,
-                               (udev->actconfig->desc.bmAttributes
-                                & USB_CONFIG_ATT_WAKEUP));
-               else if (new_state != USB_STATE_SUSPENDED)
-                       device_init_wakeup(&udev->dev, 0);
+
+               /* root hub wakeup capabilities are managed out-of-band
+                * and may involve silicon errata ... ignore them here.
+                */
+               if (udev->parent) {
+                       if (new_state == USB_STATE_CONFIGURED)
+                               device_init_wakeup(&udev->dev,
+                                       (udev->actconfig->desc.bmAttributes
+                                        & USB_CONFIG_ATT_WAKEUP));
+                       else if (new_state != USB_STATE_SUSPENDED)
+                               device_init_wakeup(&udev->dev, 0);
+               }
        } else
                recursively_mark_NOTATTACHED(udev);
        spin_unlock_irqrestore(&device_state_lock, flags);
@@ -1172,8 +1179,11 @@ static int choose_configuration(struct usb_device *udev)
        c = udev->config;
        num_configs = udev->descriptor.bNumConfigurations;
        for (i = 0; i < num_configs; (i++, c++)) {
-               struct usb_interface_descriptor *desc =
-                               &c->intf_cache[0]->altsetting->desc;
+               struct usb_interface_descriptor *desc = NULL;
+
+               /* It's possible that a config has no interfaces! */
+               if (c->desc.bNumInterfaces > 0)
+                       desc = &c->intf_cache[0]->altsetting->desc;
 
                /*
                 * HP's USB bus-powered keyboard has only one configuration
@@ -1208,7 +1218,8 @@ static int choose_configuration(struct usb_device *udev)
                /* If the first config's first interface is COMM/2/0xff
                 * (MSFT RNDIS), rule it out unless Linux has host-side
                 * RNDIS support. */
-               if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM
+               if (i == 0 && desc
+                               && desc->bInterfaceClass == USB_CLASS_COMM
                                && desc->bInterfaceSubClass == 2
                                && desc->bInterfaceProtocol == 0xff) {
 #ifndef CONFIG_USB_NET_RNDIS
@@ -1224,8 +1235,8 @@ static int choose_configuration(struct usb_device *udev)
                 * than a vendor-specific driver. */
                else if (udev->descriptor.bDeviceClass !=
                                                USB_CLASS_VENDOR_SPEC &&
-                               desc->bInterfaceClass !=
-                                               USB_CLASS_VENDOR_SPEC) {
+                               (!desc || desc->bInterfaceClass !=
+                                               USB_CLASS_VENDOR_SPEC)) {
                        best = c;
                        break;
                }
@@ -1876,18 +1887,18 @@ int usb_resume_device(struct usb_device *udev)
        if (udev->state == USB_STATE_NOTATTACHED)
                return -ENODEV;
 
-#ifdef CONFIG_USB_SUSPEND
        /* selective resume of one downstream hub-to-device port */
        if (udev->parent) {
+#ifdef CONFIG_USB_SUSPEND
                if (udev->state == USB_STATE_SUSPENDED) {
                        // NOTE swsusp may bork us, device state being wrong...
                        // NOTE this fails if parent is also suspended...
                        status = hub_port_resume(hdev_to_hub(udev->parent),
                                        udev->portnum, udev);
                } else
+#endif
                        status = 0;
        } else
-#endif
                status = finish_device_resume(udev);
        if (status < 0)
                dev_dbg(&udev->dev, "can't resume, status %d\n",
@@ -2162,7 +2173,7 @@ static int
 hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                int retry_counter)
 {
-       static DECLARE_MUTEX(usb_address0_sem);
+       static DEFINE_MUTEX(usb_address0_mutex);
 
        struct usb_device       *hdev = hub->hdev;
        int                     i, j, retval;
@@ -2183,7 +2194,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        if (oldspeed == USB_SPEED_LOW)
                delay = HUB_LONG_RESET_TIME;
 
-       down(&usb_address0_sem);
+       mutex_lock(&usb_address0_mutex);
 
        /* Reset the device; full speed may morph to high speed */
        retval = hub_port_reset(hub, port1, udev, delay);
@@ -2381,7 +2392,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 fail:
        if (retval)
                hub_port_disable(hub, port1, 0);
-       up(&usb_address0_sem);
+       mutex_unlock(&usb_address0_mutex);
        return retval;
 }
 
@@ -3017,7 +3028,7 @@ int usb_reset_device(struct usb_device *udev)
        parent_hub = hdev_to_hub(parent_hdev);
 
        /* If we're resetting an active hub, take some special actions */
-       if (udev->actconfig &&
+       if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 &&
                        udev->actconfig->interface[0]->dev.driver ==
                                &hub_driver.driver &&
                        (hub = hdev_to_hub(udev)) != NULL) {
index 7135e54..08fb20f 100644 (file)
@@ -631,8 +631,8 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
  * Returns the number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
-int usb_get_string(struct usb_device *dev, unsigned short langid,
-               unsigned char index, void *buf, int size)
+static int usb_get_string(struct usb_device *dev, unsigned short langid,
+                         unsigned char index, void *buf, int size)
 {
        int i;
        int result;
@@ -1388,11 +1388,13 @@ free_interfaces:
        if (dev->state != USB_STATE_ADDRESS)
                usb_disable_device (dev, 1);    // Skip ep0
 
-       i = dev->bus_mA - cp->desc.bMaxPower * 2;
-       if (i < 0)
-               dev_warn(&dev->dev, "new config #%d exceeds power "
-                               "limit by %dmA\n",
-                               configuration, -i);
+       if (cp) {
+               i = dev->bus_mA - cp->desc.bMaxPower * 2;
+               if (i < 0)
+                       dev_warn(&dev->dev, "new config #%d exceeds power "
+                                       "limit by %dmA\n",
+                                       configuration, -i);
+       }
 
        if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                        USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
@@ -1488,7 +1490,6 @@ EXPORT_SYMBOL(usb_sg_wait);
 // synchronous control message convenience routines
 EXPORT_SYMBOL(usb_get_descriptor);
 EXPORT_SYMBOL(usb_get_status);
-EXPORT_SYMBOL(usb_get_string);
 EXPORT_SYMBOL(usb_string);
 
 // synchronous calls that also maintain usbcore state
index fbbebab..4b55285 100644 (file)
 #include <linux/kernel.h>
 #include <linux/notifier.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 #include "usb.h"
 
 
 static struct notifier_block *usb_notifier_list;
-static DECLARE_MUTEX(usb_notifier_lock);
+static DEFINE_MUTEX(usb_notifier_lock);
 
 static void usb_notifier_chain_register(struct notifier_block **list,
                                        struct notifier_block *n)
 {
-       down(&usb_notifier_lock);
+       mutex_lock(&usb_notifier_lock);
        while (*list) {
                if (n->priority > (*list)->priority)
                        break;
@@ -30,13 +31,13 @@ static void usb_notifier_chain_register(struct notifier_block **list,
        }
        n->next = *list;
        *list = n;
-       up(&usb_notifier_lock);
+       mutex_unlock(&usb_notifier_lock);
 }
 
 static void usb_notifier_chain_unregister(struct notifier_block **nl,
                                   struct notifier_block *n)
 {
-       down(&usb_notifier_lock);
+       mutex_lock(&usb_notifier_lock);
        while ((*nl)!=NULL) {
                if ((*nl)==n) {
                        *nl = n->next;
@@ -45,7 +46,7 @@ static void usb_notifier_chain_unregister(struct notifier_block **nl,
                nl=&((*nl)->next);
        }
 exit:
-       up(&usb_notifier_lock);
+       mutex_unlock(&usb_notifier_lock);
 }
 
 static int usb_notifier_call_chain(struct notifier_block **n,
@@ -54,7 +55,7 @@ static int usb_notifier_call_chain(struct notifier_block **n,
        int ret=NOTIFY_DONE;
        struct notifier_block *nb = *n;
 
-       down(&usb_notifier_lock);
+       mutex_lock(&usb_notifier_lock);
        while (nb) {
                ret = nb->notifier_call(nb,val,v);
                if (ret&NOTIFY_STOP_MASK) {
@@ -63,7 +64,7 @@ static int usb_notifier_call_chain(struct notifier_block **n,
                nb = nb->next;
        }
 exit:
-       up(&usb_notifier_lock);
+       mutex_unlock(&usb_notifier_lock);
        return ret;
 }
 
index 13d1d36..d7352aa 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 #include <asm/scatterlist.h>
@@ -639,7 +640,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
        struct usb_bus *bus;
        struct usb_device *dev = NULL;
        
-       down(&usb_bus_list_lock);
+       mutex_lock(&usb_bus_list_lock);
        for (buslist = usb_bus_list.next;
             buslist != &usb_bus_list; 
             buslist = buslist->next) {
@@ -653,7 +654,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
                        goto exit;
        }
 exit:
-       up(&usb_bus_list_lock);
+       mutex_unlock(&usb_bus_list_lock);
        return dev;
 }
 
index ff075a5..d80f718 100644 (file)
@@ -187,6 +187,23 @@ config USB_OTG
 
           Select this only if your OMAP board has a Mini-AB connector.
 
+config USB_GADGET_AT91
+       boolean "AT91 USB Device Port"
+       depends on ARCH_AT91RM9200
+       select USB_GADGET_SELECTED
+       help
+          Many Atmel AT91 processors (such as the AT91RM2000) have a
+          full speed USB Device Port with support for five configurable
+          endpoints (plus endpoint zero).
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "at91_udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_AT91
+       tristate
+       depends on USB_GADGET_AT91
+       default USB_GADGET
 
 config USB_GADGET_DUMMY_HCD
        boolean "Dummy HCD (DEVELOPMENT)"
index d5fd04d..5a28e61 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_USB_PXA2XX)        += pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)         += goku_udc.o
 obj-$(CONFIG_USB_OMAP)         += omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)      += lh7a40x_udc.o
+obj-$(CONFIG_USB_AT91)         += at91_udc.o
 
 #
 # USB gadget drivers
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
new file mode 100644 (file)
index 0000000..865858c
--- /dev/null
@@ -0,0 +1,1773 @@
+/*
+ * at91_udc -- driver for at91-series USB peripheral controller
+ *
+ * Copyright (C) 2004 by Thomas Rathbone
+ * Copyright (C) 2005 by HP Labs
+ * Copyright (C) 2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#undef DEBUG
+#undef VERBOSE
+#undef PACKET_TRACE
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "at91_udc.h"
+
+
+/*
+ * This controller is simple and PIO-only.  It's used in many AT91-series
+ * ARMv4T controllers, including the at91rm9200 (arm920T, with MMU),
+ * at91sam9261 (arm926ejs, with MMU), and several no-mmu versions.
+ *
+ * This driver expects the board has been wired with two GPIOs suppporting
+ * a VBUS sensing IRQ, and a D+ pullup.  (They may be omitted, but the
+ * testing hasn't covered such cases.)  The pullup is most important; it
+ * provides software control over whether the host enumerates the device.
+ * The VBUS sensing helps during enumeration, and allows both USB clocks
+ * (and the transceiver) to stay gated off until they're necessary, saving
+ * power.  During USB suspend, the 48 MHz clock is gated off.
+ */
+
+#define        DRIVER_VERSION  "8 March 2005"
+
+static const char driver_name [] = "at91_udc";
+static const char ep0name[] = "ep0";
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Read from a UDP register.
+ */
+static inline unsigned long at91_udp_read(unsigned int reg)
+{
+       void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
+
+       return __raw_readl(udp_base + reg);
+}
+
+/*
+ * Write to a UDP register.
+ */
+static inline void at91_udp_write(unsigned int reg, unsigned long value)
+{
+       void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
+
+       __raw_writel(value, udp_base + reg);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+#include <linux/seq_file.h>
+
+static const char debug_filename[] = "driver/udc";
+
+#define FOURBITS "%s%s%s%s"
+#define EIGHTBITS FOURBITS FOURBITS
+
+static void proc_ep_show(struct seq_file *s, struct at91_ep *ep)
+{
+       static char             *types[] = {
+               "control", "out-iso", "out-bulk", "out-int",
+               "BOGUS",   "in-iso",  "in-bulk",  "in-int"};
+
+       u32                     csr;
+       struct at91_request     *req;
+       unsigned long   flags;
+
+       local_irq_save(flags);
+
+       csr = __raw_readl(ep->creg);
+
+       /* NOTE:  not collecting per-endpoint irq statistics... */
+
+       seq_printf(s, "\n");
+       seq_printf(s, "%s, maxpacket %d %s%s %s%s\n",
+                       ep->ep.name, ep->ep.maxpacket,
+                       ep->is_in ? "in" : "out",
+                       ep->is_iso ? " iso" : "",
+                       ep->is_pingpong
+                               ? (ep->fifo_bank ? "pong" : "ping")
+                               : "",
+                       ep->stopped ? " stopped" : "");
+       seq_printf(s, "csr %08x rxbytes=%d %s %s %s" EIGHTBITS "\n",
+               csr,
+               (csr & 0x07ff0000) >> 16,
+               (csr & (1 << 15)) ? "enabled" : "disabled",
+               (csr & (1 << 11)) ? "DATA1" : "DATA0",
+               types[(csr & 0x700) >> 8],
+
+               /* iff type is control then print current direction */
+               (!(csr & 0x700))
+                       ? ((csr & (1 << 7)) ? " IN" : " OUT")
+                       : "",
+               (csr & (1 << 6)) ? " rxdatabk1" : "",
+               (csr & (1 << 5)) ? " forcestall" : "",
+               (csr & (1 << 4)) ? " txpktrdy" : "",
+
+               (csr & (1 << 3)) ? " stallsent" : "",
+               (csr & (1 << 2)) ? " rxsetup" : "",
+               (csr & (1 << 1)) ? " rxdatabk0" : "",
+               (csr & (1 << 0)) ? " txcomp" : "");
+       if (list_empty (&ep->queue))
+               seq_printf(s, "\t(queue empty)\n");
+
+       else list_for_each_entry (req, &ep->queue, queue) {
+               unsigned        length = req->req.actual;
+
+               seq_printf(s, "\treq %p len %d/%d buf %p\n",
+                               &req->req, length,
+                               req->req.length, req->req.buf);
+       }
+       local_irq_restore(flags);
+}
+
+static void proc_irq_show(struct seq_file *s, const char *label, u32 mask)
+{
+       int i;
+
+       seq_printf(s, "%s %04x:%s%s" FOURBITS, label, mask,
+               (mask & (1 << 13)) ? " wakeup" : "",
+               (mask & (1 << 12)) ? " endbusres" : "",
+
+               (mask & (1 << 11)) ? " sofint" : "",
+               (mask & (1 << 10)) ? " extrsm" : "",
+               (mask & (1 << 9)) ? " rxrsm" : "",
+               (mask & (1 << 8)) ? " rxsusp" : "");
+       for (i = 0; i < 8; i++) {
+               if (mask & (1 << i))
+                       seq_printf(s, " ep%d", i);
+       }
+       seq_printf(s, "\n");
+}
+
+static int proc_udc_show(struct seq_file *s, void *unused)
+{
+       struct at91_udc *udc = s->private;
+       struct at91_ep  *ep;
+       u32             tmp;
+
+       seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION);
+
+       seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n",
+               udc->vbus ? "present" : "off",
+               udc->enabled
+                       ? (udc->vbus ? "active" : "enabled")
+                       : "disabled",
+               udc->selfpowered ? "self" : "VBUS",
+               udc->suspended ? ", suspended" : "",
+               udc->driver ? udc->driver->driver.name : "(none)");
+
+       /* don't access registers when interface isn't clocked */
+       if (!udc->clocked) {
+               seq_printf(s, "(not clocked)\n");
+               return 0;
+       }
+
+       tmp = at91_udp_read(AT91_UDP_FRM_NUM);
+       seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,
+               (tmp & AT91_UDP_FRM_OK) ? " ok" : "",
+               (tmp & AT91_UDP_FRM_ERR) ? " err" : "",
+               (tmp & AT91_UDP_NUM));
+
+       tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+       seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,
+               (tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",
+               (tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",
+               (tmp & AT91_UDP_ESR) ? " esr" : "",
+               (tmp & AT91_UDP_CONFG) ? " confg" : "",
+               (tmp & AT91_UDP_FADDEN) ? " fadden" : "");
+
+       tmp = at91_udp_read(AT91_UDP_FADDR);
+       seq_printf(s, "faddr   %03x:%s fadd=%d\n", tmp,
+               (tmp & AT91_UDP_FEN) ? " fen" : "",
+               (tmp & AT91_UDP_FADD));
+
+       proc_irq_show(s, "imr   ", at91_udp_read(AT91_UDP_IMR));
+       proc_irq_show(s, "isr   ", at91_udp_read(AT91_UDP_ISR));
+
+       if (udc->enabled && udc->vbus) {
+               proc_ep_show(s, &udc->ep[0]);
+               list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+                       if (ep->desc)
+                               proc_ep_show(s, ep);
+               }
+       }
+       return 0;
+}
+
+static int proc_udc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, proc_udc_show, PDE(inode)->data);
+}
+
+static struct file_operations proc_ops = {
+       .open           = proc_udc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void create_debug_file(struct at91_udc *udc)
+{
+       struct proc_dir_entry *pde;
+
+       pde = create_proc_entry (debug_filename, 0, NULL);
+       udc->pde = pde;
+       if (pde == NULL)
+               return;
+
+       pde->proc_fops = &proc_ops;
+       pde->data = udc;
+}
+
+static void remove_debug_file(struct at91_udc *udc)
+{
+       if (udc->pde)
+               remove_proc_entry(debug_filename, NULL);
+}
+
+#else
+
+static inline void create_debug_file(struct at91_udc *udc) {}
+static inline void remove_debug_file(struct at91_udc *udc) {}
+
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+static void done(struct at91_ep *ep, struct at91_request *req, int status)
+{
+       unsigned        stopped = ep->stopped;
+
+       list_del_init(&req->queue);
+       if (req->req.status == -EINPROGRESS)
+               req->req.status = status;
+       else
+               status = req->req.status;
+       if (status && status != -ESHUTDOWN)
+               VDBG("%s done %p, status %d\n", ep->ep.name, req, status);
+
+       ep->stopped = 1;
+       req->req.complete(&ep->ep, &req->req);
+       ep->stopped = stopped;
+
+       /* ep0 is always ready; other endpoints need a non-empty queue */
+       if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
+               at91_udp_write(AT91_UDP_IDR, ep->int_mask);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bits indicating OUT fifo has data ready */
+#define        RX_DATA_READY   (AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1)
+
+/*
+ * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write
+ * back most of the value you just read (because of side effects, including
+ * bits that may change after reading and before writing).
+ *
+ * Except when changing a specific bit, always write values which:
+ *  - clear SET_FX bits (setting them could change something)
+ *  - set CLR_FX bits (clearing them could change something)
+ *
+ * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE
+ * that shouldn't normally be changed.
+ */
+#define        SET_FX  (AT91_UDP_TXPKTRDY)
+#define        CLR_FX  (RX_DATA_READY | AT91_UDP_RXSETUP | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
+
+/* pull OUT packet data from the endpoint's fifo */
+static int read_fifo (struct at91_ep *ep, struct at91_request *req)
+{
+       u32 __iomem     *creg = ep->creg;
+       u8 __iomem      *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+       u32             csr;
+       u8              *buf;
+       unsigned int    count, bufferspace, is_done;
+
+       buf = req->req.buf + req->req.actual;
+       bufferspace = req->req.length - req->req.actual;
+
+       /*
+        * there might be nothing to read if ep_queue() calls us,
+        * or if we already emptied both pingpong buffers
+        */
+rescan:
+       csr = __raw_readl(creg);
+       if ((csr & RX_DATA_READY) == 0)
+               return 0;
+
+       count = (csr & AT91_UDP_RXBYTECNT) >> 16;
+       if (count > ep->ep.maxpacket)
+               count = ep->ep.maxpacket;
+       if (count > bufferspace) {
+               DBG("%s buffer overflow\n", ep->ep.name);
+               req->req.status = -EOVERFLOW;
+               count = bufferspace;
+       }
+       __raw_readsb(dreg, buf, count);
+
+       /* release and swap pingpong mem bank */
+       csr |= CLR_FX;
+       if (ep->is_pingpong) {
+               if (ep->fifo_bank == 0) {
+                       csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+                       ep->fifo_bank = 1;
+               } else {
+                       csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1);
+                       ep->fifo_bank = 0;
+               }
+       } else
+               csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+       __raw_writel(csr, creg);
+
+       req->req.actual += count;
+       is_done = (count < ep->ep.maxpacket);
+       if (count == bufferspace)
+               is_done = 1;
+
+       PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count,
+                       is_done ? " (done)" : "");
+
+       /*
+        * avoid extra trips through IRQ logic for packets already in
+        * the fifo ... maybe preventing an extra (expensive) OUT-NAK
+        */
+       if (is_done)
+               done(ep, req, 0);
+       else if (ep->is_pingpong) {
+               bufferspace -= count;
+               buf += count;
+               goto rescan;
+       }
+
+       return is_done;
+}
+
+/* load fifo for an IN packet */
+static int write_fifo(struct at91_ep *ep, struct at91_request *req)
+{
+       u32 __iomem     *creg = ep->creg;
+       u32             csr = __raw_readl(creg);
+       u8 __iomem      *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+       unsigned        total, count, is_last;
+
+       /*
+        * TODO: allow for writing two packets to the fifo ... that'll
+        * reduce the amount of IN-NAKing, but probably won't affect
+        * throughput much.  (Unlike preventing OUT-NAKing!)
+        */
+
+       /*
+        * If ep_queue() calls us, the queue is empty and possibly in
+        * odd states like TXCOMP not yet cleared (we do it, saving at
+        * least one IRQ) or the fifo not yet being free.  Those aren't
+        * issues normally (IRQ handler fast path).
+        */
+       if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) {
+               if (csr & AT91_UDP_TXCOMP) {
+                       csr |= CLR_FX;
+                       csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+                       __raw_writel(csr, creg);
+                       csr = __raw_readl(creg);
+               }
+               if (csr & AT91_UDP_TXPKTRDY)
+                       return 0;
+       }
+
+       total = req->req.length - req->req.actual;
+       if (ep->ep.maxpacket < total) {
+               count = ep->ep.maxpacket;
+               is_last = 0;
+       } else {
+               count = total;
+               is_last = (count < ep->ep.maxpacket) || !req->req.zero;
+       }
+
+       /*
+        * Write the packet, maybe it's a ZLP.
+        *
+        * NOTE:  incrementing req->actual before we receive the ACK means
+        * gadget driver IN bytecounts can be wrong in fault cases.  That's
+        * fixable with PIO drivers like this one (save "count" here, and
+        * do the increment later on TX irq), but not for most DMA hardware.
+        *
+        * So all gadget drivers must accept that potential error.  Some
+        * hardware supports precise fifo status reporting, letting them
+        * recover when the actual bytecount matters (e.g. for USB Test
+        * and Measurement Class devices).
+        */
+       __raw_writesb(dreg, req->req.buf + req->req.actual, count);
+       csr &= ~SET_FX;
+       csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+       __raw_writel(csr, creg);
+       req->req.actual += count;
+
+       PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count,
+                       is_last ? " (done)" : "");
+       if (is_last)
+               done(ep, req, 0);
+       return is_last;
+}
+
+static void nuke(struct at91_ep *ep, int status)
+{
+       struct at91_request *req;
+
+       // terminer chaque requete dans la queue
+       ep->stopped = 1;
+       if (list_empty(&ep->queue))
+               return;
+
+       VDBG("%s %s\n", __FUNCTION__, ep->ep.name);
+       while (!list_empty(&ep->queue)) {
+               req = list_entry(ep->queue.next, struct at91_request, queue);
+               done(ep, req, status);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+       struct at91_ep  *ep = container_of(_ep, struct at91_ep, ep);
+       struct at91_udc *dev = ep->udc;
+       u16             maxpacket;
+       u32             tmp;
+       unsigned long   flags;
+
+       if (!_ep || !ep
+                       || !desc || ep->desc
+                       || _ep->name == ep0name
+                       || desc->bDescriptorType != USB_DT_ENDPOINT
+                       || (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0
+                       || maxpacket > ep->maxpacket) {
+               DBG("bad ep or descriptor\n");
+               return -EINVAL;
+       }
+
+       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+               DBG("bogus device state\n");
+               return -ESHUTDOWN;
+       }
+
+       tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+       switch (tmp) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               DBG("only one control endpoint\n");
+               return -EINVAL;
+       case USB_ENDPOINT_XFER_INT:
+               if (maxpacket > 64)
+                       goto bogus_max;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               switch (maxpacket) {
+               case 8:
+               case 16:
+               case 32:
+               case 64:
+                       goto ok;
+               }
+bogus_max:
+               DBG("bogus maxpacket %d\n", maxpacket);
+               return -EINVAL;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (!ep->is_pingpong) {
+                       DBG("iso requires double buffering\n");
+                       return -EINVAL;
+               }
+               break;
+       }
+
+ok:
+       local_irq_save(flags);
+
+       /* initialize endpoint to match this descriptor */
+       ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+       ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
+       ep->stopped = 0;
+       if (ep->is_in)
+               tmp |= 0x04;
+       tmp <<= 8;
+       tmp |= AT91_UDP_EPEDS;
+       __raw_writel(tmp, ep->creg);
+
+       ep->desc = desc;
+       ep->ep.maxpacket = maxpacket;
+
+       /*
+        * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,
+        * since endpoint resets don't reset hw pingpong state.
+        */
+       at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+       at91_udp_write(AT91_UDP_RST_EP, 0);
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int at91_ep_disable (struct usb_ep * _ep)
+{
+       struct at91_ep  *ep = container_of(_ep, struct at91_ep, ep);
+       unsigned long   flags;
+
+       if (ep == &ep->udc->ep[0])
+               return -EINVAL;
+
+       local_irq_save(flags);
+
+       nuke(ep, -ESHUTDOWN);
+
+       /* restore the endpoint's pristine config */
+       ep->desc = NULL;
+       ep->ep.maxpacket = ep->maxpacket;
+
+       /* reset fifos and endpoint */
+       if (ep->udc->clocked) {
+               at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+               at91_udp_write(AT91_UDP_RST_EP, 0);
+               __raw_writel(0, ep->creg);
+       }
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+/*
+ * this is a PIO-only driver, so there's nothing
+ * interesting for request or buffer allocation.
+ */
+
+static struct usb_request *at91_ep_alloc_request (struct usb_ep *_ep, unsigned int gfp_flags)
+{
+       struct at91_request *req;
+
+       req = kcalloc(1, sizeof (struct at91_request), SLAB_KERNEL);
+       if (!req)
+               return NULL;
+
+       INIT_LIST_HEAD(&req->queue);
+       return &req->req;
+}
+
+static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct at91_request *req;
+
+       req = container_of(_req, struct at91_request, req);
+       BUG_ON(!list_empty(&req->queue));
+       kfree(req);
+}
+
+static void *at91_ep_alloc_buffer(
+       struct usb_ep *_ep,
+       unsigned bytes,
+       dma_addr_t *dma,
+       gfp_t gfp_flags)
+{
+       *dma = ~0;
+       return kmalloc(bytes, gfp_flags);
+}
+
+static void at91_ep_free_buffer(
+       struct usb_ep *ep,
+       void *buf,
+       dma_addr_t dma,
+       unsigned bytes)
+{
+       kfree(buf);
+}
+
+static int at91_ep_queue(struct usb_ep *_ep,
+                       struct usb_request *_req, gfp_t gfp_flags)
+{
+       struct at91_request     *req;
+       struct at91_ep          *ep;
+       struct at91_udc         *dev;
+       int                     status;
+       unsigned long           flags;
+
+       req = container_of(_req, struct at91_request, req);
+       ep = container_of(_ep, struct at91_ep, ep);
+
+       if (!_req || !_req->complete
+                       || !_req->buf || !list_empty(&req->queue)) {
+               DBG("invalid request\n");
+               return -EINVAL;
+       }
+
+       if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {
+               DBG("invalid ep\n");
+               return -EINVAL;
+       }
+
+       dev = ep->udc;
+
+       if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+               DBG("invalid device\n");
+               return -EINVAL;
+       }
+
+       _req->status = -EINPROGRESS;
+       _req->actual = 0;
+
+       local_irq_save(flags);
+
+       /* try to kickstart any empty and idle queue */
+       if (list_empty(&ep->queue) && !ep->stopped) {
+               int     is_ep0;
+
+               /*
+                * If this control request has a non-empty DATA stage, this
+                * will start that stage.  It works just like a non-control
+                * request (until the status stage starts, maybe early).
+                *
+                * If the data stage is empty, then this starts a successful
+                * IN/STATUS stage.  (Unsuccessful ones use set_halt.)
+                */
+               is_ep0 = (ep->ep.name == ep0name);
+               if (is_ep0) {
+                       u32     tmp;
+
+                       if (!dev->req_pending) {
+                               status = -EINVAL;
+                               goto done;
+                       }
+
+                       /*
+                        * defer changing CONFG until after the gadget driver
+                        * reconfigures the endpoints.
+                        */
+                       if (dev->wait_for_config_ack) {
+                               tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+                               tmp ^= AT91_UDP_CONFG;
+                               VDBG("toggle config\n");
+                               at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+                       }
+                       if (req->req.length == 0) {
+ep0_in_status:
+                               PACKET("ep0 in/status\n");
+                               status = 0;
+                               tmp = __raw_readl(ep->creg);
+                               tmp &= ~SET_FX;
+                               tmp |= CLR_FX | AT91_UDP_TXPKTRDY;
+                               __raw_writel(tmp, ep->creg);
+                               dev->req_pending = 0;
+                               goto done;
+                       }
+               }
+
+               if (ep->is_in)
+                       status = write_fifo(ep, req);
+               else {
+                       status = read_fifo(ep, req);
+
+                       /* IN/STATUS stage is otherwise triggered by irq */
+                       if (status && is_ep0)
+                               goto ep0_in_status;
+               }
+       } else
+               status = 0;
+
+       if (req && !status) {
+               list_add_tail (&req->queue, &ep->queue);
+               at91_udp_write(AT91_UDP_IER, ep->int_mask);
+       }
+done:
+       local_irq_restore(flags);
+       return (status < 0) ? status : 0;
+}
+
+static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct at91_ep  *ep;
+       struct at91_request     *req;
+
+       ep = container_of(_ep, struct at91_ep, ep);
+       if (!_ep || ep->ep.name == ep0name)
+               return -EINVAL;
+
+       /* make sure it's actually queued on this endpoint */
+       list_for_each_entry (req, &ep->queue, queue) {
+               if (&req->req == _req)
+                       break;
+       }
+       if (&req->req != _req)
+               return -EINVAL;
+
+       done(ep, req, -ECONNRESET);
+       return 0;
+}
+
+static int at91_ep_set_halt(struct usb_ep *_ep, int value)
+{
+       struct at91_ep  *ep = container_of(_ep, struct at91_ep, ep);
+       u32 __iomem     *creg;
+       u32             csr;
+       unsigned long   flags;
+       int             status = 0;
+
+       if (!_ep || ep->is_iso || !ep->udc->clocked)
+               return -EINVAL;
+
+       creg = ep->creg;
+       local_irq_save(flags);
+
+       csr = __raw_readl(creg);
+
+       /*
+        * fail with still-busy IN endpoints, ensuring correct sequencing
+        * of data tx then stall.  note that the fifo rx bytecount isn't
+        * completely accurate as a tx bytecount.
+        */
+       if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0))
+               status = -EAGAIN;
+       else {
+               csr |= CLR_FX;
+               csr &= ~SET_FX;
+               if (value) {
+                       csr |= AT91_UDP_FORCESTALL;
+                       VDBG("halt %s\n", ep->ep.name);
+               } else {
+                       at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+                       at91_udp_write(AT91_UDP_RST_EP, 0);
+                       csr &= ~AT91_UDP_FORCESTALL;
+               }
+               __raw_writel(csr, creg);
+       }
+
+       local_irq_restore(flags);
+       return status;
+}
+
+static struct usb_ep_ops at91_ep_ops = {
+       .enable         = at91_ep_enable,
+       .disable        = at91_ep_disable,
+       .alloc_request  = at91_ep_alloc_request,
+       .free_request   = at91_ep_free_request,
+       .alloc_buffer   = at91_ep_alloc_buffer,
+       .free_buffer    = at91_ep_free_buffer,
+       .queue          = at91_ep_queue,
+       .dequeue        = at91_ep_dequeue,
+       .set_halt       = at91_ep_set_halt,
+       // there's only imprecise fifo status reporting
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_get_frame(struct usb_gadget *gadget)
+{
+       if (!to_udc(gadget)->clocked)
+               return -EINVAL;
+       return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
+}
+
+static int at91_wakeup(struct usb_gadget *gadget)
+{
+       struct at91_udc *udc = to_udc(gadget);
+       u32             glbstate;
+       int             status = -EINVAL;
+       unsigned long   flags;
+
+       DBG("%s\n", __FUNCTION__ );
+       local_irq_save(flags);
+
+       if (!udc->clocked || !udc->suspended)
+               goto done;
+
+       /* NOTE:  some "early versions" handle ESR differently ... */
+
+       glbstate = at91_udp_read(AT91_UDP_GLB_STAT);
+       if (!(glbstate & AT91_UDP_ESR))
+               goto done;
+       glbstate |= AT91_UDP_ESR;
+       at91_udp_write(AT91_UDP_GLB_STAT, glbstate);
+
+done:
+       local_irq_restore(flags);
+       return status;
+}
+
+/* reinit == restore inital software state */
+static void udc_reinit(struct at91_udc *udc)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&udc->gadget.ep_list);
+       INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+       for (i = 0; i < NUM_ENDPOINTS; i++) {
+               struct at91_ep *ep = &udc->ep[i];
+
+               if (i != 0)
+                       list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+               ep->desc = NULL;
+               ep->stopped = 0;
+               ep->fifo_bank = 0;
+               ep->ep.maxpacket = ep->maxpacket;
+               // initialiser une queue par endpoint
+               INIT_LIST_HEAD(&ep->queue);
+       }
+}
+
+static void stop_activity(struct at91_udc *udc)
+{
+       struct usb_gadget_driver *driver = udc->driver;
+       int i;
+
+       if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+               driver = NULL;
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+       for (i = 0; i < NUM_ENDPOINTS; i++) {
+               struct at91_ep *ep = &udc->ep[i];
+               ep->stopped = 1;
+               nuke(ep, -ESHUTDOWN);
+       }
+       if (driver)
+               driver->disconnect(&udc->gadget);
+
+       udc_reinit(udc);
+}
+
+static void clk_on(struct at91_udc *udc)
+{
+       if (udc->clocked)
+               return;
+       udc->clocked = 1;
+       clk_enable(udc->iclk);
+       clk_enable(udc->fclk);
+}
+
+static void clk_off(struct at91_udc *udc)
+{
+       if (!udc->clocked)
+               return;
+       udc->clocked = 0;
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       clk_disable(udc->iclk);
+       clk_disable(udc->fclk);
+}
+
+/*
+ * activate/deactivate link with host; minimize power usage for
+ * inactive links by cutting clocks and transceiver power.
+ */
+static void pullup(struct at91_udc *udc, int is_on)
+{
+       if (!udc->enabled || !udc->vbus)
+               is_on = 0;
+       DBG("%sactive\n", is_on ? "" : "in");
+       if (is_on) {
+               clk_on(udc);
+               at91_udp_write(AT91_UDP_TXVC, 0);
+               at91_set_gpio_value(udc->board.pullup_pin, 1);
+       } else  {
+               stop_activity(udc);
+               at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+               at91_set_gpio_value(udc->board.pullup_pin, 0);
+               clk_off(udc);
+
+               // REVISIT:  with transceiver disabled, will D- float
+               // so that a host would falsely detect a device?
+       }
+}
+
+/* vbus is here!  turn everything on that's ready */
+static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+       struct at91_udc *udc = to_udc(gadget);
+       unsigned long   flags;
+
+       // VDBG("vbus %s\n", is_active ? "on" : "off");
+       local_irq_save(flags);
+       udc->vbus = (is_active != 0);
+       pullup(udc, is_active);
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int at91_pullup(struct usb_gadget *gadget, int is_on)
+{
+       struct at91_udc *udc = to_udc(gadget);
+       unsigned long   flags;
+
+       local_irq_save(flags);
+       udc->enabled = is_on = !!is_on;
+       pullup(udc, is_on);
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+       struct at91_udc *udc = to_udc(gadget);
+       unsigned long   flags;
+
+       local_irq_save(flags);
+       udc->selfpowered = (is_on != 0);
+       local_irq_restore(flags);
+       return 0;
+}
+
+static const struct usb_gadget_ops at91_udc_ops = {
+       .get_frame              = at91_get_frame,
+       .wakeup                 = at91_wakeup,
+       .set_selfpowered        = at91_set_selfpowered,
+       .vbus_session           = at91_vbus_session,
+       .pullup                 = at91_pullup,
+
+       /*
+        * VBUS-powered devices may also also want to support bigger
+        * power budgets after an appropriate SET_CONFIGURATION.
+        */
+       // .vbus_power          = at91_vbus_power,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int handle_ep(struct at91_ep *ep)
+{
+       struct at91_request     *req;
+       u32 __iomem             *creg = ep->creg;
+       u32                     csr = __raw_readl(creg);
+
+       if (!list_empty(&ep->queue))
+               req = list_entry(ep->queue.next,
+                       struct at91_request, queue);
+       else
+               req = NULL;
+
+       if (ep->is_in) {
+               if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) {
+                       csr |= CLR_FX;
+                       csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP);
+                       __raw_writel(csr, creg);
+               }
+               if (req)
+                       return write_fifo(ep, req);
+
+       } else {
+               if (csr & AT91_UDP_STALLSENT) {
+                       /* STALLSENT bit == ISOERR */
+                       if (ep->is_iso && req)
+                               req->req.status = -EILSEQ;
+                       csr |= CLR_FX;
+                       csr &= ~(SET_FX | AT91_UDP_STALLSENT);
+                       __raw_writel(csr, creg);
+                       csr = __raw_readl(creg);
+               }
+               if (req && (csr & RX_DATA_READY))
+                       return read_fifo(ep, req);
+       }
+       return 0;
+}
+
+union setup {
+       u8                      raw[8];
+       struct usb_ctrlrequest  r;
+};
+
+static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+{
+       u32 __iomem     *creg = ep->creg;
+       u8 __iomem      *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+       unsigned        rxcount, i = 0;
+       u32             tmp;
+       union setup     pkt;
+       int             status = 0;
+
+       /* read and ack SETUP; hard-fail for bogus packets */
+       rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16;
+       if (likely(rxcount == 8)) {
+               while (rxcount--)
+                       pkt.raw[i++] = __raw_readb(dreg);
+               if (pkt.r.bRequestType & USB_DIR_IN) {
+                       csr |= AT91_UDP_DIR;
+                       ep->is_in = 1;
+               } else {
+                       csr &= ~AT91_UDP_DIR;
+                       ep->is_in = 0;
+               }
+       } else {
+               // REVISIT this happens sometimes under load; why??
+               ERR("SETUP len %d, csr %08x\n", rxcount, csr);
+               status = -EINVAL;
+       }
+       csr |= CLR_FX;
+       csr &= ~(SET_FX | AT91_UDP_RXSETUP);
+       __raw_writel(csr, creg);
+       udc->wait_for_addr_ack = 0;
+       udc->wait_for_config_ack = 0;
+       ep->stopped = 0;
+       if (unlikely(status != 0))
+               goto stall;
+
+#define w_index                le16_to_cpu(pkt.r.wIndex)
+#define w_value                le16_to_cpu(pkt.r.wValue)
+#define w_length       le16_to_cpu(pkt.r.wLength)
+
+       VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
+                       pkt.r.bRequestType, pkt.r.bRequest,
+                       w_value, w_index, w_length);
+
+       /*
+        * A few standard requests get handled here, ones that touch
+        * hardware ... notably for device and endpoint features.
+        */
+       udc->req_pending = 1;
+       csr = __raw_readl(creg);
+       csr |= CLR_FX;
+       csr &= ~SET_FX;
+       switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) {
+
+       case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+                       | USB_REQ_SET_ADDRESS:
+               __raw_writel(csr | AT91_UDP_TXPKTRDY, creg);
+               udc->addr = w_value;
+               udc->wait_for_addr_ack = 1;
+               udc->req_pending = 0;
+               /* FADDR is set later, when we ack host STATUS */
+               return;
+
+       case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+                       | USB_REQ_SET_CONFIGURATION:
+               tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
+               if (pkt.r.wValue)
+                       udc->wait_for_config_ack = (tmp == 0);
+               else
+                       udc->wait_for_config_ack = (tmp != 0);
+               if (udc->wait_for_config_ack)
+                       VDBG("wait for config\n");
+               /* CONFG is toggled later, if gadget driver succeeds */
+               break;
+
+       /*
+        * Hosts may set or clear remote wakeup status, and
+        * devices may report they're VBUS powered.
+        */
+       case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+                       | USB_REQ_GET_STATUS:
+               tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+               if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
+                       tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+               PACKET("get device status\n");
+               __raw_writeb(tmp, dreg);
+               __raw_writeb(0, dreg);
+               goto write_in;
+               /* then STATUS starts later, automatically */
+       case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+                       | USB_REQ_SET_FEATURE:
+               if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+                       goto stall;
+               tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+               tmp |= AT91_UDP_ESR;
+               at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+               goto succeed;
+       case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+                       | USB_REQ_CLEAR_FEATURE:
+               if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+                       goto stall;
+               tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+               tmp &= ~AT91_UDP_ESR;
+               at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+               goto succeed;
+
+       /*
+        * Interfaces have no feature settings; this is pretty useless.
+        * we won't even insist the interface exists...
+        */
+       case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+                       | USB_REQ_GET_STATUS:
+               PACKET("get interface status\n");
+               __raw_writeb(0, dreg);
+               __raw_writeb(0, dreg);
+               goto write_in;
+               /* then STATUS starts later, automatically */
+       case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+                       | USB_REQ_SET_FEATURE:
+       case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+                       | USB_REQ_CLEAR_FEATURE:
+               goto stall;
+
+       /*
+        * Hosts may clear bulk/intr endpoint halt after the gadget
+        * driver sets it (not widely used); or set it (for testing)
+        */
+       case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+                       | USB_REQ_GET_STATUS:
+               tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+               ep = &udc->ep[tmp];
+               if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc))
+                       goto stall;
+
+               if (tmp) {
+                       if ((w_index & USB_DIR_IN)) {
+                               if (!ep->is_in)
+                                       goto stall;
+                       } else if (ep->is_in)
+                               goto stall;
+               }
+               PACKET("get %s status\n", ep->ep.name);
+               if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL)
+                       tmp = (1 << USB_ENDPOINT_HALT);
+               else
+                       tmp = 0;
+               __raw_writeb(tmp, dreg);
+               __raw_writeb(0, dreg);
+               goto write_in;
+               /* then STATUS starts later, automatically */
+       case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+                       | USB_REQ_SET_FEATURE:
+               tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+               ep = &udc->ep[tmp];
+               if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+                       goto stall;
+               if (!ep->desc || ep->is_iso)
+                       goto stall;
+               if ((w_index & USB_DIR_IN)) {
+                       if (!ep->is_in)
+                               goto stall;
+               } else if (ep->is_in)
+                       goto stall;
+
+               tmp = __raw_readl(ep->creg);
+               tmp &= ~SET_FX;
+               tmp |= CLR_FX | AT91_UDP_FORCESTALL;
+               __raw_writel(tmp, ep->creg);
+               goto succeed;
+       case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+                       | USB_REQ_CLEAR_FEATURE:
+               tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+               ep = &udc->ep[tmp];
+               if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+                       goto stall;
+               if (tmp == 0)
+                       goto succeed;
+               if (!ep->desc || ep->is_iso)
+                       goto stall;
+               if ((w_index & USB_DIR_IN)) {
+                       if (!ep->is_in)
+                               goto stall;
+               } else if (ep->is_in)
+                       goto stall;
+
+               at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+               at91_udp_write(AT91_UDP_RST_EP, 0);
+               tmp = __raw_readl(ep->creg);
+               tmp |= CLR_FX;
+               tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
+               __raw_writel(tmp, ep->creg);
+               if (!list_empty(&ep->queue))
+                       handle_ep(ep);
+               goto succeed;
+       }
+
+#undef w_value
+#undef w_index
+#undef w_length
+
+       /* pass request up to the gadget driver */
+       status = udc->driver->setup(&udc->gadget, &pkt.r);
+       if (status < 0) {
+stall:
+               VDBG("req %02x.%02x protocol STALL; stat %d\n",
+                               pkt.r.bRequestType, pkt.r.bRequest, status);
+               csr |= AT91_UDP_FORCESTALL;
+               __raw_writel(csr, creg);
+               udc->req_pending = 0;
+       }
+       return;
+
+succeed:
+       /* immediate successful (IN) STATUS after zero length DATA */
+       PACKET("ep0 in/status\n");
+write_in:
+       csr |= AT91_UDP_TXPKTRDY;
+       __raw_writel(csr, creg);
+       udc->req_pending = 0;
+       return;
+}
+
+static void handle_ep0(struct at91_udc *udc)
+{
+       struct at91_ep          *ep0 = &udc->ep[0];
+       u32 __iomem             *creg = ep0->creg;
+       u32                     csr = __raw_readl(creg);
+       struct at91_request     *req;
+
+       if (unlikely(csr & AT91_UDP_STALLSENT)) {
+               nuke(ep0, -EPROTO);
+               udc->req_pending = 0;
+               csr |= CLR_FX;
+               csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL);
+               __raw_writel(csr, creg);
+               VDBG("ep0 stalled\n");
+               csr = __raw_readl(creg);
+       }
+       if (csr & AT91_UDP_RXSETUP) {
+               nuke(ep0, 0);
+               udc->req_pending = 0;
+               handle_setup(udc, ep0, csr);
+               return;
+       }
+
+       if (list_empty(&ep0->queue))
+               req = NULL;
+       else
+               req = list_entry(ep0->queue.next, struct at91_request, queue);
+
+       /* host ACKed an IN packet that we sent */
+       if (csr & AT91_UDP_TXCOMP) {
+               csr |= CLR_FX;
+               csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+
+               /* write more IN DATA? */
+               if (req && ep0->is_in) {
+                       if (handle_ep(ep0))
+                               udc->req_pending = 0;
+
+               /*
+                * Ack after:
+                *  - last IN DATA packet (including GET_STATUS)
+                *  - IN/STATUS for OUT DATA
+                *  - IN/STATUS for any zero-length DATA stage
+                * except for the IN DATA case, the host should send
+                * an OUT status later, which we'll ack.
+                */
+               } else {
+                       udc->req_pending = 0;
+                       __raw_writel(csr, creg);
+
+                       /*
+                        * SET_ADDRESS takes effect only after the STATUS
+                        * (to the original address) gets acked.
+                        */
+                       if (udc->wait_for_addr_ack) {
+                               u32     tmp;
+
+                               at91_udp_write(AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr);
+                               tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+                               tmp &= ~AT91_UDP_FADDEN;
+                               if (udc->addr)
+                                       tmp |= AT91_UDP_FADDEN;
+                               at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+
+                               udc->wait_for_addr_ack = 0;
+                               VDBG("address %d\n", udc->addr);
+                       }
+               }
+       }
+
+       /* OUT packet arrived ... */
+       else if (csr & AT91_UDP_RX_DATA_BK0) {
+               csr |= CLR_FX;
+               csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+
+               /* OUT DATA stage */
+               if (!ep0->is_in) {
+                       if (req) {
+                               if (handle_ep(ep0)) {
+                                       /* send IN/STATUS */
+                                       PACKET("ep0 in/status\n");
+                                       csr = __raw_readl(creg);
+                                       csr &= ~SET_FX;
+                                       csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+                                       __raw_writel(csr, creg);
+                                       udc->req_pending = 0;
+                               }
+                       } else if (udc->req_pending) {
+                               /*
+                                * AT91 hardware has a hard time with this
+                                * "deferred response" mode for control-OUT
+                                * transfers.  (For control-IN it's fine.)
+                                *
+                                * The normal solution leaves OUT data in the
+                                * fifo until the gadget driver is ready.
+                                * We couldn't do that here without disabling
+                                * the IRQ that tells about SETUP packets,
+                                * e.g. when the host gets impatient...
+                                *
+                                * Working around it by copying into a buffer
+                                * would almost be a non-deferred response,
+                                * except that it wouldn't permit reliable
+                                * stalling of the request.  Instead, demand
+                                * that gadget drivers not use this mode.
+                                */
+                               DBG("no control-OUT deferred responses!\n");
+                               __raw_writel(csr | AT91_UDP_FORCESTALL, creg);
+                               udc->req_pending = 0;
+                       }
+
+               /* STATUS stage for control-IN; ack.  */
+               } else {
+                       PACKET("ep0 out/status ACK\n");
+                       __raw_writel(csr, creg);
+
+                       /* "early" status stage */
+                       if (req)
+                               done(ep0, req, 0);
+               }
+       }
+}
+
+static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
+{
+       struct at91_udc         *udc = _udc;
+       u32                     rescans = 5;
+
+       while (rescans--) {
+               u32     status = at91_udp_read(AT91_UDP_ISR);
+
+               status &= at91_udp_read(AT91_UDP_IMR);
+               if (!status)
+                       break;
+
+               /* USB reset irq:  not maskable */
+               if (status & AT91_UDP_ENDBUSRES) {
+                       at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
+                       at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS);
+                       /* Atmel code clears this irq twice */
+                       at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+                       at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+                       VDBG("end bus reset\n");
+                       udc->addr = 0;
+                       stop_activity(udc);
+
+                       /* enable ep0 */
+                       at91_udp_write(AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
+                       udc->gadget.speed = USB_SPEED_FULL;
+                       udc->suspended = 0;
+                       at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
+
+                       /*
+                        * NOTE:  this driver keeps clocks off unless the
+                        * USB host is present.  That saves power, and also
+                        * eliminates IRQs (reset, resume, suspend) that can
+                        * otherwise flood from the controller.  If your
+                        * board doesn't support VBUS detection, suspend and
+                        * resume irq logic may need more attention...
+                        */
+
+               /* host initiated suspend (3+ms bus idle) */
+               } else if (status & AT91_UDP_RXSUSP) {
+                       at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP);
+                       at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM);
+                       at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP);
+                       // VDBG("bus suspend\n");
+                       if (udc->suspended)
+                               continue;
+                       udc->suspended = 1;
+
+                       /*
+                        * NOTE:  when suspending a VBUS-powered device, the
+                        * gadget driver should switch into slow clock mode
+                        * and then into standby to avoid drawing more than
+                        * 500uA power (2500uA for some high-power configs).
+                        */
+                       if (udc->driver && udc->driver->suspend)
+                               udc->driver->suspend(&udc->gadget);
+
+               /* host initiated resume */
+               } else if (status & AT91_UDP_RXRSM) {
+                       at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM);
+                       at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP);
+                       at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM);
+                       // VDBG("bus resume\n");
+                       if (!udc->suspended)
+                               continue;
+                       udc->suspended = 0;
+
+                       /*
+                        * NOTE:  for a VBUS-powered device, the gadget driver
+                        * would normally want to switch out of slow clock
+                        * mode into normal mode.
+                        */
+                       if (udc->driver && udc->driver->resume)
+                               udc->driver->resume(&udc->gadget);
+
+               /* endpoint IRQs are cleared by handling them */
+               } else {
+                       int             i;
+                       unsigned        mask = 1;
+                       struct at91_ep  *ep = &udc->ep[1];
+
+                       if (status & mask)
+                               handle_ep0(udc);
+                       for (i = 1; i < NUM_ENDPOINTS; i++) {
+                               mask <<= 1;
+                               if (status & mask)
+                                       handle_ep(ep);
+                               ep++;
+                       }
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct at91_udc controller = {
+       .gadget = {
+               .ops = &at91_udc_ops,
+               .ep0 = &controller.ep[0].ep,
+               .name = driver_name,
+               .dev = {
+                       .bus_id = "gadget"
+               }
+       },
+       .ep[0] = {
+               .ep = {
+                       .name   = ep0name,
+                       .ops    = &at91_ep_ops,
+               },
+               .udc            = &controller,
+               .maxpacket      = 8,
+               .creg           = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(0)),
+               .int_mask       = 1 << 0,
+       },
+       .ep[1] = {
+               .ep = {
+                       .name   = "ep1",
+                       .ops    = &at91_ep_ops,
+               },
+               .udc            = &controller,
+               .is_pingpong    = 1,
+               .maxpacket      = 64,
+               .creg           = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(1)),
+               .int_mask       = 1 << 1,
+       },
+       .ep[2] = {
+               .ep = {
+                       .name   = "ep2",
+                       .ops    = &at91_ep_ops,
+               },
+               .udc            = &controller,
+               .is_pingpong    = 1,
+               .maxpacket      = 64,
+               .creg           = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(2)),
+               .int_mask       = 1 << 2,
+       },
+       .ep[3] = {
+               .ep = {
+                       /* could actually do bulk too */
+                       .name   = "ep3-int",
+                       .ops    = &at91_ep_ops,
+               },
+               .udc            = &controller,
+               .maxpacket      = 8,
+               .creg           = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(3)),
+               .int_mask       = 1 << 3,
+       },
+       .ep[4] = {
+               .ep = {
+                       .name   = "ep4",
+                       .ops    = &at91_ep_ops,
+               },
+               .udc            = &controller,
+               .is_pingpong    = 1,
+               .maxpacket      = 256,
+               .creg           = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(4)),
+               .int_mask       = 1 << 4,
+       },
+       .ep[5] = {
+               .ep = {
+                       .name   = "ep5",
+                       .ops    = &at91_ep_ops,
+               },
+               .udc            = &controller,
+               .is_pingpong    = 1,
+               .maxpacket      = 256,
+               .creg           = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(5)),
+               .int_mask       = 1 << 5,
+       },
+       /* ep6 and ep7 are also reserved */
+};
+
+static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r)
+{
+       struct at91_udc *udc = _udc;
+       unsigned        value;
+
+       /* vbus needs at least brief debouncing */
+       udelay(10);
+       value = at91_get_gpio_value(udc->board.vbus_pin);
+       if (value != udc->vbus)
+               at91_vbus_session(&udc->gadget, value);
+
+       return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+       struct at91_udc *udc = &controller;
+       int             retval;
+
+       if (!driver
+                       || driver->speed != USB_SPEED_FULL
+                       || !driver->bind
+                       || !driver->unbind
+                       || !driver->setup) {
+               DBG("bad parameter.\n");
+               return -EINVAL;
+       }
+
+       if (udc->driver) {
+               DBG("UDC already has a gadget driver\n");
+               return -EBUSY;
+       }
+
+       udc->driver = driver;
+       udc->gadget.dev.driver = &driver->driver;
+       udc->gadget.dev.driver_data = &driver->driver;
+       udc->enabled = 1;
+       udc->selfpowered = 1;
+
+       retval = driver->bind(&udc->gadget);
+       if (retval) {
+               DBG("driver->bind() returned %d\n", retval);
+               udc->driver = NULL;
+               return retval;
+       }
+
+       local_irq_disable();
+       pullup(udc, 1);
+       local_irq_enable();
+
+       DBG("bound to %s\n", driver->driver.name);
+       return 0;
+}
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+       struct at91_udc *udc = &controller;
+
+       if (!driver || driver != udc->driver)
+               return -EINVAL;
+
+       local_irq_disable();
+       udc->enabled = 0;
+       pullup(udc, 0);
+       local_irq_enable();
+
+       driver->unbind(&udc->gadget);
+       udc->driver = NULL;
+
+       DBG("unbound from %s\n", driver->driver.name);
+       return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+
+static void at91udc_shutdown(struct platform_device *dev)
+{
+       /* force disconnect on reboot */
+       pullup(platform_get_drvdata(dev), 0);
+}
+
+static int __devinit at91udc_probe(struct platform_device *pdev)
+{
+       struct device   *dev = &pdev->dev;
+       struct at91_udc *udc;
+       int             retval;
+
+       if (!dev->platform_data) {
+               /* small (so we copy it) but critical! */
+               DBG("missing platform_data\n");
+               return -ENODEV;
+       }
+
+       if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) {
+               DBG("someone's using UDC memory\n");
+               return -EBUSY;
+       }
+
+       /* init software state */
+       udc = &controller;
+       udc->gadget.dev.parent = dev;
+       udc->board = *(struct at91_udc_data *) dev->platform_data;
+       udc->pdev = pdev;
+       udc_reinit(udc);
+       udc->enabled = 0;
+
+       /* get interface and function clocks */
+       udc->iclk = clk_get(dev, "udc_clk");
+       udc->fclk = clk_get(dev, "udpck");
+       if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
+               DBG("clocks missing\n");
+               return -ENODEV;
+       }
+
+       retval = device_register(&udc->gadget.dev);
+       if (retval < 0)
+               goto fail0;
+
+       /* disable everything until there's a gadget driver and vbus */
+       pullup(udc, 0);
+
+       /* request UDC and maybe VBUS irqs */
+       if (request_irq(AT91_ID_UDP, at91_udc_irq, SA_INTERRUPT, driver_name, udc)) {
+               DBG("request irq %d failed\n", AT91_ID_UDP);
+               retval = -EBUSY;
+               goto fail1;
+       }
+       if (udc->board.vbus_pin > 0) {
+               if (request_irq(udc->board.vbus_pin, at91_vbus_irq, SA_INTERRUPT, driver_name, udc)) {
+                       DBG("request vbus irq %d failed\n", udc->board.vbus_pin);
+                       free_irq(AT91_ID_UDP, udc);
+                       retval = -EBUSY;
+                       goto fail1;
+               }
+       } else {
+               DBG("no VBUS detection, assuming always-on\n");
+               udc->vbus = 1;
+       }
+       dev_set_drvdata(dev, udc);
+       create_debug_file(udc);
+
+       INFO("%s version %s\n", driver_name, DRIVER_VERSION);
+       return 0;
+
+fail1:
+       device_unregister(&udc->gadget.dev);
+fail0:
+       release_mem_region(AT91_VA_BASE_UDP, SZ_16K);
+       DBG("%s probe failed, %d\n", driver_name, retval);
+       return retval;
+}
+
+static int __devexit at91udc_remove(struct platform_device *dev)
+{
+       struct at91_udc *udc = platform_get_drvdata(dev);
+
+       DBG("remove\n");
+
+       pullup(udc, 0);
+
+       if (udc->driver != 0)
+               usb_gadget_unregister_driver(udc->driver);
+
+       remove_debug_file(udc);
+       if (udc->board.vbus_pin > 0)
+               free_irq(udc->board.vbus_pin, udc);
+       free_irq(AT91_ID_UDP, udc);
+       device_unregister(&udc->gadget.dev);
+       release_mem_region(AT91_BASE_UDP, SZ_16K);
+
+       clk_put(udc->iclk);
+       clk_put(udc->fclk);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int at91udc_suspend(struct platform_device *dev, u32 state, u32 level)
+{
+       struct at91_udc *udc = platform_get_drvdata(dev);
+
+       /*
+        * The "safe" suspend transitions are opportunistic ... e.g. when
+        * the USB link is suspended (48MHz clock autogated off), or when
+        * it's disconnected (programmatically gated off, elsewhere).
+        * Then we can suspend, and the chip can enter slow clock mode.
+        *
+        * The problem case is some component (user mode?) suspending this
+        * device while it's active, with the 48 MHz clock in use.  There
+        * are two basic approaches:  (a) veto suspend levels involving slow
+        * clock mode, (b) disconnect, so 48 MHz will no longer be in use
+        * and we can enter slow clock mode.  This uses (b) for now, since
+        * it's simplest until AT91 PM exists and supports the other option.
+        */
+       if (udc->vbus && !udc->suspended)
+               pullup(udc, 0);
+       return 0;
+}
+
+static int at91udc_resume(struct platform_device *dev, u32 level)
+{
+       struct at91_udc *udc = platform_get_drvdata(dev);
+
+       /* maybe reconnect to host; if so, clocks on */
+       pullup(udc, 1);
+       return 0;
+}
+#else
+#define        at91udc_suspend NULL
+#define        at91udc_resume  NULL
+#endif
+
+static struct platform_driver at91_udc = {
+       .probe          = at91udc_probe,
+       .remove         = __devexit_p(at91udc_remove),
+       .shutdown       = at91udc_shutdown,
+       .suspend        = at91udc_suspend,
+       .resume         = at91udc_resume,
+       .driver         = {
+               .name   = (char *) driver_name,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __devinit udc_init_module(void)
+{
+       return platform_driver_register(&at91_udc);
+}
+module_init(udc_init_module);
+
+static void __devexit udc_exit_module(void)
+{
+       platform_driver_unregister(&at91_udc);
+}
+module_exit(udc_exit_module);
+
+MODULE_DESCRIPTION("AT91RM9200 udc driver");
+MODULE_AUTHOR("Thomas Rathbone, David Brownell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
new file mode 100644 (file)
index 0000000..5a4799c
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2004 by Thomas Rathbone, HP Labs
+ * Copyright (C) 2005 by Ivan Kokshaysky
+ * Copyright (C) 2006 by SAN People
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef AT91_UDC_H
+#define AT91_UDC_H
+
+/*
+ * USB Device Port (UDP) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ */
+
+#define AT91_UDP_FRM_NUM       0x00            /* Frame Number Register */
+#define     AT91_UDP_NUM       (0x7ff <<  0)   /* Frame Number */
+#define     AT91_UDP_FRM_ERR   (1     << 16)   /* Frame Error */
+#define     AT91_UDP_FRM_OK    (1     << 17)   /* Frame OK */
+
+#define AT91_UDP_GLB_STAT      0x04            /* Global State Register */
+#define     AT91_UDP_FADDEN    (1 <<  0)       /* Function Address Enable */
+#define     AT91_UDP_CONFG     (1 <<  1)       /* Configured */
+#define     AT91_UDP_ESR       (1 <<  2)       /* Enable Send Resume */
+#define     AT91_UDP_RSMINPR   (1 <<  3)       /* Resume has been sent */
+#define     AT91_UDP_RMWUPE    (1 <<  4)       /* Remote Wake Up Enable */
+
+#define AT91_UDP_FADDR         0x08            /* Function Address Register */
+#define     AT91_UDP_FADD      (0x7f << 0)     /* Function Address Value */
+#define     AT91_UDP_FEN       (1    << 8)     /* Function Enable */
+
+#define AT91_UDP_IER           0x10            /* Interrupt Enable Register */
+#define AT91_UDP_IDR           0x14            /* Interrupt Disable Register */
+#define AT91_UDP_IMR           0x18            /* Interrupt Mask Register */
+
+#define AT91_UDP_ISR           0x1c            /* Interrupt Status Register */
+#define     AT91_UDP_EP(n)     (1 << (n))      /* Endpoint Interrupt Status */
+#define     AT91_UDP_RXSUSP    (1 <<  8)       /* USB Suspend Interrupt Status */
+#define     AT91_UDP_RXRSM     (1 <<  9)       /* USB Resume Interrupt Status */
+#define     AT91_UDP_EXTRSM    (1 << 10)       /* External Resume Interrupt Status */
+#define     AT91_UDP_SOFINT    (1 << 11)       /* Start of Frame Interrupt Status */
+#define     AT91_UDP_ENDBUSRES (1 << 12)       /* End of Bus Reset Interrpt Status */
+#define     AT91_UDP_WAKEUP    (1 << 13)       /* USB Wakeup Interrupt Status */
+
+#define AT91_UDP_ICR           0x20            /* Interrupt Clear Register */
+#define AT91_UDP_RST_EP                0x28            /* Reset Endpoint Register */
+
+#define AT91_UDP_CSR(n)                (0x30+((n)*4))  /* Endpoint Control/Status Registers 0-7 */
+#define     AT91_UDP_TXCOMP    (1 <<  0)       /* Generates IN packet with data previously written in DPR */
+#define     AT91_UDP_RX_DATA_BK0 (1 <<  1)     /* Receive Data Bank 0 */
+#define     AT91_UDP_RXSETUP   (1 <<  2)       /* Send STALL to the host */
+#define     AT91_UDP_STALLSENT (1 <<  3)       /* Stall Sent / Isochronous error (Isochronous endpoints) */
+#define     AT91_UDP_TXPKTRDY  (1 <<  4)       /* Transmit Packet Ready */
+#define     AT91_UDP_FORCESTALL        (1 <<  5)       /* Force Stall */
+#define     AT91_UDP_RX_DATA_BK1 (1 <<  6)     /* Receive Data Bank 1 */
+#define     AT91_UDP_DIR       (1 <<  7)       /* Transfer Direction */
+#define     AT91_UDP_EPTYPE    (7 <<  8)       /* Endpoint Type */
+#define                AT91_UDP_EPTYPE_CTRL            (0 <<  8)
+#define                AT91_UDP_EPTYPE_ISO_OUT         (1 <<  8)
+#define                AT91_UDP_EPTYPE_BULK_OUT        (2 <<  8)
+#define                AT91_UDP_EPTYPE_INT_OUT         (3 <<  8)
+#define                AT91_UDP_EPTYPE_ISO_IN          (5 <<  8)
+#define                AT91_UDP_EPTYPE_BULK_IN         (6 <<  8)
+#define                AT91_UDP_EPTYPE_INT_IN          (7 <<  8)
+#define     AT91_UDP_DTGLE     (1 << 11)       /* Data Toggle */
+#define     AT91_UDP_EPEDS     (1 << 15)       /* Endpoint Enable/Disable */
+#define     AT91_UDP_RXBYTECNT (0x7ff << 16)   /* Number of bytes in FIFO */
+
+#define AT91_UDP_FDR(n)                (0x50+((n)*4))  /* Endpoint FIFO Data Registers 0-7 */
+
+#define AT91_UDP_TXVC          0x74            /* Transceiver Control Register */
+#define     AT91_UDP_TXVC_TXVDIS (1 << 8)      /* Transceiver Disable */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * controller driver data structures
+ */
+
+#define        NUM_ENDPOINTS   6
+
+/*
+ * hardware won't disable bus reset, or resume while the controller
+ * is suspended ... watching suspend helps keep the logic symmetric.
+ */
+#define        MINIMUS_INTERRUPTUS \
+       (AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP)
+
+struct at91_ep {
+       struct usb_ep                   ep;
+       struct list_head                queue;
+       struct at91_udc                 *udc;
+       void __iomem                    *creg;
+
+       unsigned                        maxpacket:16;
+       u8                              int_mask;
+       unsigned                        is_pingpong:1;
+
+       unsigned                        stopped:1;
+       unsigned                        is_in:1;
+       unsigned                        is_iso:1;
+       unsigned                        fifo_bank:1;
+
+       const struct usb_endpoint_descriptor
+                                       *desc;
+};
+
+/*
+ * driver is non-SMP, and just blocks IRQs whenever it needs
+ * access protection for chip registers or driver state
+ */
+struct at91_udc {
+       struct usb_gadget               gadget;
+       struct at91_ep                  ep[NUM_ENDPOINTS];
+       struct usb_gadget_driver        *driver;
+       unsigned                        vbus:1;
+       unsigned                        enabled:1;
+       unsigned                        clocked:1;
+       unsigned                        suspended:1;
+       unsigned                        req_pending:1;
+       unsigned                        wait_for_addr_ack:1;
+       unsigned                        wait_for_config_ack:1;
+       unsigned                        selfpowered:1;
+       u8                              addr;
+       struct at91_udc_data            board;
+       struct clk                      *iclk, *fclk;
+       struct platform_device          *pdev;
+       struct proc_dir_entry           *pde;
+};
+
+static inline struct at91_udc *to_udc(struct usb_gadget *g)
+{
+       return container_of(g, struct at91_udc, gadget);
+}
+
+struct at91_request {
+       struct usb_request              req;
+       struct list_head                queue;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)          printk(KERN_DEBUG "udc: " stuff)
+#else
+#define DBG(stuff...)          do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG               DBG
+#else
+#    define VDBG(stuff...)     do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+#    define PACKET             VDBG
+#else
+#    define PACKET(stuff...)   do{}while(0)
+#endif
+
+#define ERR(stuff...)          printk(KERN_ERR "udc: " stuff)
+#define WARN(stuff...)         printk(KERN_WARNING "udc: " stuff)
+#define INFO(stuff...)         printk(KERN_INFO "udc: " stuff)
+
+#endif
+
index 9734cb7..42ce41d 100644 (file)
@@ -478,10 +478,9 @@ dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
                return NULL;
        ep = usb_ep_to_dummy_ep (_ep);
 
-       req = kmalloc (sizeof *req, mem_flags);
+       req = kzalloc(sizeof(*req), mem_flags);
        if (!req)
                return NULL;
-       memset (req, 0, sizeof *req);
        INIT_LIST_HEAD (&req->queue);
        return &req->req;
 }
index afc84cf..c3d8e5c 100644 (file)
@@ -182,33 +182,37 @@ struct eth_dev {
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  */
 
-static ushort __initdata idVendor;
+static ushort idVendor;
 module_param(idVendor, ushort, S_IRUGO);
 MODULE_PARM_DESC(idVendor, "USB Vendor ID");
 
-static ushort __initdata idProduct;
+static ushort idProduct;
 module_param(idProduct, ushort, S_IRUGO);
 MODULE_PARM_DESC(idProduct, "USB Product ID");
 
-static ushort __initdata bcdDevice;
+static ushort bcdDevice;
 module_param(bcdDevice, ushort, S_IRUGO);
 MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
 
-static char *__initdata iManufacturer;
+static char *iManufacturer;
 module_param(iManufacturer, charp, S_IRUGO);
 MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
 
-static char *__initdata iProduct;
+static char *iProduct;
 module_param(iProduct, charp, S_IRUGO);
 MODULE_PARM_DESC(iProduct, "USB Product string");
 
+static char *iSerialNumber;
+module_param(iSerialNumber, charp, S_IRUGO);
+MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
+
 /* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
-static char *__initdata dev_addr;
+static char *dev_addr;
 module_param(dev_addr, charp, S_IRUGO);
 MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
 
 /* this address is invisible to ifconfig */
-static char *__initdata host_addr;
+static char *host_addr;
 module_param(host_addr, charp, S_IRUGO);
 MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 
@@ -253,6 +257,14 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_MUSBHSFC
+#define DEV_CONFIG_CDC
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSBHDRC
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -395,6 +407,7 @@ static inline int BITRATE(struct usb_gadget *g)
 #define STRING_CDC                     7
 #define STRING_SUBSET                  8
 #define STRING_RNDIS                   9
+#define STRING_SERIALNUMBER            10
 
 /* holds our biggest descriptor (or RNDIS response) */
 #define USB_BUFSIZ     256
@@ -862,6 +875,7 @@ static inline void __init hs_subset_descriptors(void)
 
 static char                            manufacturer [50];
 static char                            product_desc [40] = DRIVER_DESC;
+static char                            serial_number [20];
 
 #ifdef DEV_CONFIG_CDC
 /* address that the host will use ... usually assigned at random */
@@ -872,6 +886,7 @@ static char                         ethaddr [2 * ETH_ALEN + 1];
 static struct usb_string               strings [] = {
        { STRING_MANUFACTURER,  manufacturer, },
        { STRING_PRODUCT,       product_desc, },
+       { STRING_SERIALNUMBER,  serial_number, },
        { STRING_DATA,          "Ethernet Data", },
 #ifdef DEV_CONFIG_CDC
        { STRING_CDC,           "CDC Ethernet", },
@@ -1549,7 +1564,8 @@ static int eth_change_mtu (struct net_device *net, int new_mtu)
 {
        struct eth_dev  *dev = netdev_priv(net);
 
-       // FIXME if rndis, don't change while link's live
+       if (dev->rndis)
+               return -EBUSY;
 
        if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
                return -ERANGE;
@@ -2116,7 +2132,7 @@ eth_req_free (struct usb_ep *ep, struct usb_request *req)
 }
 
 
-static void
+static void __exit
 eth_unbind (struct usb_gadget *gadget)
 {
        struct eth_dev          *dev = get_gadget_data (gadget);
@@ -2153,7 +2169,7 @@ static u8 __init nibble (unsigned char c)
        return 0;
 }
 
-static void __init get_ether_addr (const char *str, u8 *dev_addr)
+static int __init get_ether_addr(const char *str, u8 *dev_addr)
 {
        if (str) {
                unsigned        i;
@@ -2168,9 +2184,10 @@ static void __init get_ether_addr (const char *str, u8 *dev_addr)
                        dev_addr [i] = num;
                }
                if (is_valid_ether_addr (dev_addr))
-                       return;
+                       return 0;
        }
        random_ether_addr(dev_addr);
+       return 1;
 }
 
 static int __init
@@ -2268,6 +2285,10 @@ eth_bind (struct usb_gadget *gadget)
                strlcpy (manufacturer, iManufacturer, sizeof manufacturer);
        if (iProduct)
                strlcpy (product_desc, iProduct, sizeof product_desc);
+       if (iSerialNumber) {
+               device_desc.iSerialNumber = STRING_SERIALNUMBER,
+               strlcpy(serial_number, iSerialNumber, sizeof serial_number);
+       }
 
        /* all we really need is bulk IN/OUT */
        usb_ep_autoconfig_reset (gadget);
@@ -2377,9 +2398,13 @@ autoconf_fail:
         * The host side address is used with CDC and RNDIS, and commonly
         * ends up in a persistent config database.
         */
-       get_ether_addr(dev_addr, net->dev_addr);
+       if (get_ether_addr(dev_addr, net->dev_addr))
+               dev_warn(&gadget->dev,
+                       "using random %s ethernet address\n", "self");
        if (cdc || rndis) {
-               get_ether_addr(host_addr, dev->host_mac);
+               if (get_ether_addr(host_addr, dev->host_mac))
+                       dev_warn(&gadget->dev,
+                               "using random %s ethernet address\n", "host");
 #ifdef DEV_CONFIG_CDC
                snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
                        dev->host_mac [0], dev->host_mac [1],
@@ -2523,7 +2548,7 @@ static struct usb_gadget_driver eth_driver = {
 
        .function       = (char *) driver_desc,
        .bind           = eth_bind,
-       .unbind         = eth_unbind,
+       .unbind         = __exit_p(eth_unbind),
 
        .setup          = eth_setup,
        .disconnect     = eth_disconnect,
index de59c58..cf3be29 100644 (file)
@@ -3678,7 +3678,7 @@ static void lun_release(struct device *dev)
        kref_put(&fsg->ref, fsg_release);
 }
 
-static void fsg_unbind(struct usb_gadget *gadget)
+static void __exit fsg_unbind(struct usb_gadget *gadget)
 {
        struct fsg_dev          *fsg = get_gadget_data(gadget);
        int                     i;
@@ -4064,7 +4064,7 @@ static struct usb_gadget_driver           fsg_driver = {
 #endif
        .function       = (char *) longname,
        .bind           = fsg_bind,
-       .unbind         = fsg_unbind,
+       .unbind         = __exit_p(fsg_unbind),
        .disconnect     = fsg_disconnect,
        .setup          = fsg_setup,
        .suspend        = fsg_suspend,
index 8cbae21..c408140 100644 (file)
@@ -3,9 +3,9 @@
  * gadget drivers or other code that needs to deal with them, and which
  * autoconfigures instead of using early binding to the hardware.
  *
- * This could eventually work like the ARM mach_is_*() stuff, driven by
+ * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
  * some config file that gets updated as new hardware is supported.
- * (And avoiding the runtime comparisons in typical one-choice cases.)
+ * (And avoiding all runtime comparisons in typical one-choice configs!)
  *
  * NOTE:  some of these controller drivers may not be available yet.
  */
 #define gadget_is_imx(g)       0
 #endif
 
+/* Mentor high speed function controller */
+#ifdef CONFIG_USB_GADGET_MUSBHSFC
+#define gadget_is_musbhsfc(g)  !strcmp("musbhsfc_udc", (g)->name)
+#else
+#define gadget_is_musbhsfc(g)  0
+#endif
+
+/* Mentor high speed "dual role" controller, peripheral mode */
+#ifdef CONFIG_USB_GADGET_MUSBHDRC
+#define gadget_is_musbhdrc(g)  !strcmp("musbhdrc_udc", (g)->name)
+#else
+#define gadget_is_musbhdrc(g)  0
+#endif
+
+#ifdef CONFIG_USB_GADGET_MPC8272
+#define gadget_is_mpc8272(g)   !strcmp("mpc8272_udc", (g)->name)
+#else
+#define gadget_is_mpc8272(g)   0
+#endif
+
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
 // ...
@@ -143,5 +163,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x13;
        else if (gadget_is_imx(gadget))
                return 0x14;
+       else if (gadget_is_musbhsfc(gadget))
+               return 0x15;
+       else if (gadget_is_musbhdrc(gadget))
+               return 0x16;
+       else if (gadget_is_mpc8272(gadget))
+               return 0x17;
        return -ENOENT;
 }
index b0f3cd6..66b81bb 100644 (file)
@@ -275,11 +275,10 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
 
        if (!_ep)
                return NULL;
-       req = kmalloc(sizeof *req, gfp_flags);
+       req = kzalloc(sizeof *req, gfp_flags);
        if (!req)
                return NULL;
 
-       memset(req, 0, sizeof *req);
        req->req.dma = DMA_ADDR_INVALID;
        INIT_LIST_HEAD(&req->queue);
        return &req->req;
index 0aab7d2..b44cfda 100644 (file)
@@ -170,10 +170,9 @@ static struct dev_data *dev_new (void)
 {
        struct dev_data         *dev;
 
-       dev = kmalloc (sizeof *dev, GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return NULL;
-       memset (dev, 0, sizeof *dev);
        dev->state = STATE_DEV_DISABLED;
        atomic_set (&dev->count, 1);
        spin_lock_init (&dev->lock);
@@ -1592,10 +1591,9 @@ static int activate_ep_files (struct dev_data *dev)
        gadget_for_each_ep (ep, dev->gadget) {
                struct ep_data  *data;
 
-               data = kmalloc (sizeof *data, GFP_KERNEL);
+               data = kzalloc(sizeof(*data), GFP_KERNEL);
                if (!data)
                        goto enomem;
-               memset (data, 0, sizeof data);
                data->state = STATE_EP_DISABLED;
                init_MUTEX (&data->lock);
                init_waitqueue_head (&data->wait);
index 1a362c5..0d3424e 100644 (file)
@@ -1114,11 +1114,10 @@ static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep,
 
        DEBUG("%s, %p\n", __FUNCTION__, ep);
 
-       req = kmalloc(sizeof *req, gfp_flags);
+       req = kzalloc(sizeof(*req), gfp_flags);
        if (!req)
                return 0;
 
-       memset(req, 0, sizeof *req);
        INIT_LIST_HEAD(&req->queue);
 
        return &req->req;
index 67b13ab..fb73dc1 100644 (file)
@@ -386,11 +386,10 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
                return NULL;
        ep = container_of (_ep, struct net2280_ep, ep);
 
-       req = kmalloc (sizeof *req, gfp_flags);
+       req = kzalloc(sizeof(*req), gfp_flags);
        if (!req)
                return NULL;
 
-       memset (req, 0, sizeof *req);
        req->req.dma = DMA_ADDR_INVALID;
        INIT_LIST_HEAD (&req->queue);
 
index a8972d7..fbea514 100644 (file)
@@ -273,9 +273,8 @@ omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
 {
        struct omap_req *req;
 
-       req = kmalloc(sizeof *req, gfp_flags);
+       req = kzalloc(sizeof(*req), gfp_flags);
        if (req) {
-               memset (req, 0, sizeof *req);
                req->req.dma = DMA_ADDR_INVALID;
                INIT_LIST_HEAD (&req->queue);
        }
@@ -2586,11 +2585,10 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
        /* UDC_PULLUP_EN gates the chip clock */
        // OTG_SYSCON_1_REG |= DEV_IDLE_EN;
 
-       udc = kmalloc (sizeof *udc, SLAB_KERNEL);
+       udc = kzalloc(sizeof(*udc), SLAB_KERNEL);
        if (!udc)
                return -ENOMEM;
 
-       memset(udc, 0, sizeof *udc);
        spin_lock_init (&udc->lock);
 
        udc->gadget.ops = &omap_gadget_ops;
index bb028c5..680f7fc 100644 (file)
@@ -335,11 +335,10 @@ pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
 {
        struct pxa2xx_request *req;
 
-       req = kmalloc (sizeof *req, gfp_flags);
+       req = kzalloc(sizeof(*req), gfp_flags);
        if (!req)
                return NULL;
 
-       memset (req, 0, sizeof *req);
        INIT_LIST_HEAD (&req->queue);
        return &req->req;
 }
index ba9acd5..b992546 100644 (file)
@@ -369,7 +369,7 @@ static struct usb_gadget_driver gs_gadget_driver = {
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
        .function =             GS_LONG_NAME,
        .bind =                 gs_bind,
-       .unbind =               gs_unbind,
+       .unbind =               __exit_p(gs_unbind),
        .setup =                gs_setup,
        .disconnect =           gs_disconnect,
        .driver = {
@@ -1413,7 +1413,7 @@ requeue:
  * Called on module load.  Allocates and initializes the device
  * structure and a control request.
  */
-static int gs_bind(struct usb_gadget *gadget)
+static int __init gs_bind(struct usb_gadget *gadget)
 {
        int ret;
        struct usb_ep *ep;
@@ -1538,7 +1538,7 @@ autoconf_fail:
  * Called on module unload.  Frees the control request and device
  * structure.
  */
-static void gs_unbind(struct usb_gadget *gadget)
+static void __exit gs_unbind(struct usb_gadget *gadget)
 {
        struct gs_dev *dev = get_gadget_data(gadget);
 
@@ -2178,10 +2178,9 @@ static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags)
                return -EIO;
 
        for (i=0; i<GS_NUM_PORTS; i++) {
-               if ((port=(struct gs_port *)kmalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
+               if ((port=kzalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
                        return -ENOMEM;
 
-               memset(port, 0, sizeof(struct gs_port));
                port->port_dev = dev;
                port->port_num = i;
                port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
index ae7a1c0..51424f6 100644 (file)
@@ -1119,7 +1119,7 @@ zero_autoresume (unsigned long _dev)
 
 /*-------------------------------------------------------------------------*/
 
-static void
+static void __exit
 zero_unbind (struct usb_gadget *gadget)
 {
        struct zero_dev         *dev = get_gadget_data (gadget);
@@ -1136,7 +1136,7 @@ zero_unbind (struct usb_gadget *gadget)
        set_gadget_data (gadget, NULL);
 }
 
-static int
+static int __init
 zero_bind (struct usb_gadget *gadget)
 {
        struct zero_dev         *dev;
@@ -1188,10 +1188,9 @@ autoconf_fail:
 
 
        /* ok, we made sense of the hardware ... */
-       dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+       dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
        if (!dev)
                return -ENOMEM;
-       memset (dev, 0, sizeof *dev);
        spin_lock_init (&dev->lock);
        dev->gadget = gadget;
        set_gadget_data (gadget, dev);
@@ -1224,12 +1223,6 @@ autoconf_fail:
                loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       if (gadget->is_otg) {
-               otg_descriptor.bmAttributes |= USB_OTG_HNP,
-               source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-               loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
        usb_gadget_set_selfpowered (gadget);
 
        init_timer (&dev->resume);
@@ -1294,7 +1287,7 @@ static struct usb_gadget_driver zero_driver = {
 #endif
        .function       = (char *) longname,
        .bind           = zero_bind,
-       .unbind         = zero_unbind,
+       .unbind         = __exit_p(zero_unbind),
 
        .setup          = zero_setup,
        .disconnect     = zero_disconnect,
index be3fd9b..e27b79a 100644 (file)
@@ -6,7 +6,7 @@ comment "USB Host Controller Drivers"
 
 config USB_EHCI_HCD
        tristate "EHCI HCD (USB 2.0) support"
-       depends on USB && PCI
+       depends on USB && USB_ARCH_HAS_EHCI
        ---help---
          The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
          "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
new file mode 100644 (file)
index 0000000..63eadee
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * EHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * Bus Glue for AMD Alchemy Au1xxx
+ *
+ * Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Modified for AMD Alchemy Au1200 EHC
+ *  by K.Boge <karsten.boge@amd.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/platform_device.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#ifndef CONFIG_SOC_AU1200
+#error "this Alchemy chip doesn't have EHCI"
+#else                          /* Au1200 */
+
+#define USB_HOST_CONFIG   (USB_MSR_BASE + USB_MSR_MCFG)
+#define USB_MCFG_PFEN     (1<<31)
+#define USB_MCFG_RDCOMB   (1<<30)
+#define USB_MCFG_SSDEN    (1<<23)
+#define USB_MCFG_PHYPLLEN (1<<19)
+#define USB_MCFG_EHCCLKEN (1<<17)
+#define USB_MCFG_UCAM     (1<<7)
+#define USB_MCFG_EBMEN    (1<<3)
+#define USB_MCFG_EMEMEN   (1<<2)
+
+#define USBH_ENABLE_CE    (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN)
+
+#ifdef CONFIG_DMA_COHERENT
+#define USBH_ENABLE_INIT  (USBH_ENABLE_CE \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN | USB_MCFG_UCAM \
+                         | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+#else
+#define USBH_ENABLE_INIT  (USBH_ENABLE_CE \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN \
+                         | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+#endif
+#define USBH_DISABLE      (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+
+#endif                         /* Au1200 */
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void au1xxx_start_ehc(struct platform_device *dev)
+{
+       pr_debug(__FILE__ ": starting Au1xxx EHCI USB Controller\n");
+
+       /* write HW defaults again in case Yamon cleared them */
+       if (au_readl(USB_HOST_CONFIG) == 0) {
+               au_writel(0x00d02000, USB_HOST_CONFIG);
+               au_readl(USB_HOST_CONFIG);
+               udelay(1000);
+       }
+       /* enable host controller */
+       au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+       au_readl(USB_HOST_CONFIG);
+       udelay(1000);
+       au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG),
+                 USB_HOST_CONFIG);
+       au_readl(USB_HOST_CONFIG);
+       udelay(1000);
+
+       pr_debug(__FILE__ ": Clock to USB host has been enabled\n");
+}
+
+static void au1xxx_stop_ehc(struct platform_device *dev)
+{
+       pr_debug(__FILE__ ": stopping Au1xxx EHCI USB Controller\n");
+
+       /* Disable mem */
+       au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+       udelay(1000);
+       /* Disable clock */
+       au_writel(~USB_MCFG_EHCCLKEN & au_readl(USB_HOST_CONFIG),
+                 USB_HOST_CONFIG);
+       au_readl(USB_HOST_CONFIG);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_ehci_au1xxx_probe - initialize Au1xxx-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
+                         struct usb_hcd **hcd_out, struct platform_device *dev)
+{
+       int retval;
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+
+#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
+
+       /* Au1200 AB USB does not support coherent memory */
+       if (!(read_c0_prid() & 0xff)) {
+               pr_info("%s: this is chip revision AB!\n", dev->dev.name);
+               pr_info("%s: update your board or re-configure the kernel\n",
+                       dev->dev.name);
+               return -ENODEV;
+       }
+#endif
+
+       au1xxx_start_ehc(dev);
+
+       if (dev->resource[1].flags != IORESOURCE_IRQ) {
+               pr_debug("resource[1] is not IORESOURCE_IRQ");
+               retval = -ENOMEM;
+       }
+       hcd = usb_create_hcd(driver, &dev->dev, "Au1xxx");
+       if (!hcd)
+               return -ENOMEM;
+       hcd->rsrc_start = dev->resource[0].start;
+       hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               pr_debug("request_mem_region failed");
+               retval = -EBUSY;
+               goto err1;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               pr_debug("ioremap failed");
+               retval = -ENOMEM;
+               goto err2;
+       }
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+       /* cache this readonly data; minimize chip reads */
+       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+       /* ehci_hcd_init(hcd_to_ehci(hcd)); */
+
+       retval =
+           usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
+       if (retval == 0)
+               return retval;
+
+       au1xxx_stop_ehc(dev);
+       iounmap(hcd->regs);
+err2:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+       usb_put_hcd(hcd);
+       return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_ehci_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_ehci_hcd_au1xxx_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_ehci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
+{
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+       au1xxx_stop_ehc(dev);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ehci_au1xxx_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "Au1xxx EHCI",
+       .hcd_priv_size = sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq = ehci_irq,
+       .flags = HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset = ehci_init,
+       .start = ehci_run,
+       .stop = ehci_stop,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue = ehci_urb_enqueue,
+       .urb_dequeue = ehci_urb_dequeue,
+       .endpoint_disable = ehci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data = ehci_hub_status_data,
+       .hub_control = ehci_hub_control,
+#ifdef CONFIG_PM
+       .hub_suspend = ehci_hub_suspend,
+       .hub_resume = ehci_hub_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct usb_hcd *hcd = NULL;
+       int ret;
+
+       pr_debug("In ehci_hcd_au1xxx_drv_probe\n");
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev);
+       return ret;
+}
+
+static int ehci_hcd_au1xxx_drv_remove(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       usb_ehci_au1xxx_remove(hcd, pdev);
+       return 0;
+}
+
+ /*TBD*/
+/*static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       return 0;
+}
+static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       return 0;
+}
+*/
+static struct device_driver ehci_hcd_au1xxx_driver = {
+       .name = "au1xxx-ehci",
+       .bus = &platform_bus_type,
+       .probe = ehci_hcd_au1xxx_drv_probe,
+       .remove = ehci_hcd_au1xxx_drv_remove,
+       /*.suspend      = ehci_hcd_au1xxx_drv_suspend, */
+       /*.resume       = ehci_hcd_au1xxx_drv_resume, */
+};
+
+static int __init ehci_hcd_au1xxx_init(void)
+{
+       pr_debug(DRIVER_INFO " (Au1xxx)\n");
+
+       return driver_register(&ehci_hcd_au1xxx_driver);
+}
+
+static void __exit ehci_hcd_au1xxx_cleanup(void)
+{
+       driver_unregister(&ehci_hcd_au1xxx_driver);
+}
+
+module_init(ehci_hcd_au1xxx_init);
+module_exit(ehci_hcd_au1xxx_cleanup);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
new file mode 100644 (file)
index 0000000..f985f12
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * (C) Copyright David Brownell 2000-2002
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
+ * by Hunter Wu.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+
+#include "ehci-fsl.h"
+
+/* FIXME: Power Managment is un-ported so temporarily disable it */
+#undef CONFIG_PM
+
+/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_fsl_probe - initialize FSL-based HCDs
+ * @drvier: Driver to be used for this HCD
+ * @pdev: USB Host Controller being probed
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller.
+ *
+ */
+int usb_hcd_fsl_probe(const struct hc_driver *driver,
+                     struct platform_device *pdev)
+{
+       struct fsl_usb2_platform_data *pdata;
+       struct usb_hcd *hcd;
+       struct resource *res;
+       int irq;
+       int retval;
+       unsigned int temp;
+
+       pr_debug("initializing FSL-SOC USB Controller\n");
+
+       /* Need platform data for setup */
+       pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev,
+                       "No platform data for %s.\n", pdev->dev.bus_id);
+               return -ENODEV;
+       }
+
+       /*
+        * This is a host mode driver, verify that we're supposed to be
+        * in host mode.
+        */
+       if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
+             (pdata->operating_mode == FSL_USB2_MPH_HOST))) {
+               dev_err(&pdev->dev,
+                       "Non Host Mode configured for %s. Wrong driver linked.\n",
+                       pdev->dev.bus_id);
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Found HC with no IRQ. Check %s setup!\n",
+                       pdev->dev.bus_id);
+               return -ENODEV;
+       }
+       irq = res->start;
+
+       hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto err1;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Found HC with no register addr. Check %s setup!\n",
+                       pdev->dev.bus_id);
+               retval = -ENODEV;
+               goto err2;
+       }
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = res->end - res->start + 1;
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+                               driver->description)) {
+               dev_dbg(&pdev->dev, "controller already in use\n");
+               retval = -EBUSY;
+               goto err2;
+       }
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+
+       if (hcd->regs == NULL) {
+               dev_dbg(&pdev->dev, "error mapping memory\n");
+               retval = -EFAULT;
+               goto err3;
+       }
+
+       /* Enable USB controller */
+       temp = in_be32(hcd->regs + 0x500);
+       out_be32(hcd->regs + 0x500, temp | 0x4);
+
+       /* Set to Host mode */
+       temp = in_le32(hcd->regs + 0x1a8);
+       out_le32(hcd->regs + 0x1a8, temp | 0x3);
+
+       retval = usb_add_hcd(hcd, irq, SA_SHIRQ);
+       if (retval != 0)
+               goto err4;
+       return retval;
+
+      err4:
+       iounmap(hcd->regs);
+      err3:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+      err2:
+       usb_put_hcd(hcd);
+      err1:
+       dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval);
+       return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_fsl_probe().
+ *
+ */
+void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+}
+
+static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
+                             enum fsl_usb2_phy_modes phy_mode,
+                             unsigned int port_offset)
+{
+       u32 portsc = 0;
+       switch (phy_mode) {
+       case FSL_USB2_PHY_ULPI:
+               portsc |= PORT_PTS_ULPI;
+               break;
+       case FSL_USB2_PHY_SERIAL:
+               portsc |= PORT_PTS_SERIAL;
+               break;
+       case FSL_USB2_PHY_UTMI_WIDE:
+               portsc |= PORT_PTS_PTW;
+               /* fall through */
+       case FSL_USB2_PHY_UTMI:
+               portsc |= PORT_PTS_UTMI;
+               break;
+       case FSL_USB2_PHY_NONE:
+               break;
+       }
+       writel(portsc, &ehci->regs->port_status[port_offset]);
+}
+
+static void mpc83xx_usb_setup(struct usb_hcd *hcd)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       struct fsl_usb2_platform_data *pdata;
+       void __iomem *non_ehci = hcd->regs;
+
+       pdata =
+           (struct fsl_usb2_platform_data *)hcd->self.controller->
+           platform_data;
+       /* Enable PHY interface in the control reg. */
+       out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
+       out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+
+       if (pdata->operating_mode == FSL_USB2_DR_HOST)
+               mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+
+       if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
+               unsigned int chip, rev, svr;
+
+               svr = mfspr(SPRN_SVR);
+               chip = svr >> 16;
+               rev = (svr >> 4) & 0xf;
+
+               /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
+               if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055))
+                       ehci->has_fsl_port_bug = 1;
+
+               if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
+                       mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+               if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
+                       mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
+       }
+
+       /* put controller in host mode. */
+       writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+       out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
+       out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
+       out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+}
+
+/* called after powerup, by probe or system-pm "wakeup" */
+static int ehci_fsl_reinit(struct ehci_hcd *ehci)
+{
+       mpc83xx_usb_setup(ehci_to_hcd(ehci));
+       ehci_port_power(ehci, 0);
+
+       return 0;
+}
+
+/* called during probe() after chip reset completes */
+static int ehci_fsl_setup(struct usb_hcd *hcd)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       int retval;
+
+       /* EHCI registers start at offset 0x100 */
+       ehci->caps = hcd->regs + 0x100;
+       ehci->regs = hcd->regs + 0x100 +
+           HC_LENGTH(readl(&ehci->caps->hc_capbase));
+       dbg_hcs_params(ehci, "reset");
+       dbg_hcc_params(ehci, "reset");
+
+       /* cache this readonly data; minimize chip reads */
+       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+       retval = ehci_halt(ehci);
+       if (retval)
+               return retval;
+
+       /* data structure init */
+       retval = ehci_init(hcd);
+       if (retval)
+               return retval;
+
+       ehci->is_tdi_rh_tt = 1;
+
+       ehci->sbrn = 0x20;
+
+       ehci_reset(ehci);
+
+       retval = ehci_fsl_reinit(ehci);
+       return retval;
+}
+
+static const struct hc_driver ehci_fsl_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "Freescale On-Chip EHCI Host Controller",
+       .hcd_priv_size = sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq = ehci_irq,
+       .flags = HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset = ehci_fsl_setup,
+       .start = ehci_run,
+#ifdef CONFIG_PM
+       .suspend = ehci_bus_suspend,
+       .resume = ehci_bus_resume,
+#endif
+       .stop = ehci_stop,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue = ehci_urb_enqueue,
+       .urb_dequeue = ehci_urb_dequeue,
+       .endpoint_disable = ehci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data = ehci_hub_status_data,
+       .hub_control = ehci_hub_control,
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
+};
+
+static int ehci_fsl_drv_probe(struct platform_device *pdev)
+{
+       if (usb_disabled())
+               return -ENODEV;
+
+       return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev);
+}
+
+static int ehci_fsl_drv_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_hcd_fsl_remove(hcd, pdev);
+
+       return 0;
+}
+
+static struct platform_driver ehci_fsl_dr_driver = {
+       .probe = ehci_fsl_drv_probe,
+       .remove = ehci_fsl_drv_remove,
+       .driver = {
+                  .name = "fsl-usb2-dr",
+                  },
+};
+
+static struct platform_driver ehci_fsl_mph_driver = {
+       .probe = ehci_fsl_drv_probe,
+       .remove = ehci_fsl_drv_remove,
+       .driver = {
+                  .name = "fsl-usb2-mph",
+                  },
+};
+
+static int __init ehci_fsl_init(void)
+{
+       int retval;
+
+       pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
+                hcd_name,
+                sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
+                sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
+
+       retval = platform_driver_register(&ehci_fsl_dr_driver);
+       if (retval)
+               return retval;
+
+       return platform_driver_register(&ehci_fsl_mph_driver);
+}
+
+static void __exit ehci_fsl_cleanup(void)
+{
+       platform_driver_unregister(&ehci_fsl_mph_driver);
+       platform_driver_unregister(&ehci_fsl_dr_driver);
+}
+
+module_init(ehci_fsl_init);
+module_exit(ehci_fsl_cleanup);
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
new file mode 100644 (file)
index 0000000..caac0d1
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (c) 2005 freescale semiconductor
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _EHCI_FSL_H
+#define _EHCI_FSL_H
+
+/* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_ULPIVP     0x170
+#define FSL_SOC_USB_PORTSC1    0x184
+#define PORT_PTS_MSK           (3<<30)
+#define PORT_PTS_UTMI          (0<<30)
+#define PORT_PTS_ULPI          (2<<30)
+#define        PORT_PTS_SERIAL         (3<<30)
+#define PORT_PTS_PTW           (1<<28)
+#define FSL_SOC_USB_PORTSC2    0x188
+#define FSL_SOC_USB_USBMODE    0x1a8
+#define FSL_SOC_USB_SNOOP1     0x400   /* NOTE: big-endian */
+#define FSL_SOC_USB_SNOOP2     0x404   /* NOTE: big-endian */
+#define FSL_SOC_USB_AGECNTTHRSH        0x408   /* NOTE: big-endian */
+#define FSL_SOC_USB_SICTRL     0x40c   /* NOTE: big-endian */
+#define FSL_SOC_USB_PRICTRL    0x410   /* NOTE: big-endian */
+#define FSL_SOC_USB_CTRL       0x500   /* NOTE: big-endian */
+#endif                         /* _EHCI_FSL_H */
index 9dd3d14..79f2d8b 100644 (file)
@@ -889,8 +889,19 @@ MODULE_LICENSE ("GPL");
 
 #ifdef CONFIG_PCI
 #include "ehci-pci.c"
+#define        EHCI_BUS_GLUED
 #endif
 
-#if !defined(CONFIG_PCI)
+#ifdef CONFIG_PPC_83xx
+#include "ehci-fsl.c"
+#define        EHCI_BUS_GLUED
+#endif
+
+#ifdef CONFIG_SOC_AU1X00
+#include "ehci-au1xxx.c"
+#define        EHCI_BUS_GLUED
+#endif
+
+#ifndef        EHCI_BUS_GLUED
 #error "missing bus glue for ehci-hcd"
 #endif
index 69b0b9b..d03e3ca 100644 (file)
@@ -359,6 +359,8 @@ static int ehci_hub_control (
                case USB_PORT_FEAT_SUSPEND:
                        if (temp & PORT_RESET)
                                goto error;
+                       if (ehci->no_selective_suspend)
+                               break;
                        if (temp & PORT_SUSPEND) {
                                if ((temp & PORT_PE) == 0)
                                        goto error;
@@ -514,6 +516,8 @@ static int ehci_hub_control (
                temp &= ~PORT_RWC_BITS;
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
+                       if (ehci->no_selective_suspend)
+                               break;
                        if ((temp & PORT_PE) == 0
                                        || (temp & PORT_RESET) != 0)
                                goto error;
index 91c2ab4..766061e 100644 (file)
@@ -75,7 +75,6 @@ static void qh_destroy (struct kref *kref)
        }
        if (qh->dummy)
                ehci_qtd_free (ehci, qh->dummy);
-       usb_put_dev (qh->dev);
        dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
 }
 
@@ -221,13 +220,9 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
                ehci->periodic [i] = EHCI_LIST_END;
 
        /* software shadow of hardware table */
-       ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
-       if (ehci->pshadow == NULL) {
-               goto fail;
-       }
-       memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
-
-       return 0;
+       ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
+       if (ehci->pshadow != NULL)
+               return 0;
 
 fail:
        ehci_dbg (ehci, "couldn't init memory\n");
index 3a6687d..1e03f1a 100644 (file)
@@ -106,11 +106,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                }
                break;
        case PCI_VENDOR_ID_NVIDIA:
+               switch (pdev->device) {
                /* NVidia reports that certain chips don't handle
                 * QH, ITD, or SITD addresses above 2GB.  (But TD,
                 * data buffer, and periodic schedule are normal.)
                 */
-               switch (pdev->device) {
                case 0x003c:    /* MCP04 */
                case 0x005b:    /* CK804 */
                case 0x00d8:    /* CK8 */
@@ -120,6 +120,14 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                                ehci_warn(ehci, "can't enable NVidia "
                                        "workaround for >2GB RAM\n");
                        break;
+               /* Some NForce2 chips have problems with selective suspend;
+                * fixed in newer silicon.
+                */
+               case 0x0068:
+                       pci_read_config_dword(pdev, PCI_REVISION_ID, &temp);
+                       if ((temp & 0xff) < 0xa4)
+                               ehci->no_selective_suspend = 1;
+                       break;
                }
                break;
        }
@@ -163,6 +171,21 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                        device_init_wakeup(&pdev->dev, 1);
        }
 
+#ifdef CONFIG_USB_SUSPEND
+       /* REVISIT: the controller works fine for wakeup iff the root hub
+        * itself is "globally" suspended, but usbcore currently doesn't
+        * understand such things.
+        *
+        * System suspend currently expects to be able to suspend the entire
+        * device tree, device-at-a-time.  If we failed selective suspend
+        * reports, system suspend would fail; so the root hub code must claim
+        * success.  That's lying to usbcore, and it matters for for runtime
+        * PM scenarios with selective suspend and remote wakeup...
+        */
+       if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
+               ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
+#endif
+
        retval = ehci_pci_reinit(ehci, pdev);
 done:
        return retval;
index 9b13bf2..e469221 100644 (file)
@@ -702,7 +702,7 @@ qh_make (
        }
 
        /* support for tt scheduling, and access to toggles */
-       qh->dev = usb_get_dev (urb->dev);
+       qh->dev = urb->dev;
 
        /* using TT? */
        switch (urb->dev->speed) {
@@ -721,7 +721,14 @@ qh_make (
                info1 |= maxp << 16;
 
                info2 |= (EHCI_TUNE_MULT_TT << 30);
-               info2 |= urb->dev->ttport << 23;
+
+               /* Some Freescale processors have an erratum in which the
+                * port number in the queue head was 0..N-1 instead of 1..N.
+                */
+               if (ehci_has_fsl_portno_bug(ehci))
+                       info2 |= (urb->dev->ttport-1) << 23;
+               else
+                       info2 |= urb->dev->ttport << 23;
 
                /* set the address of the TT; for TDI's integrated
                 * root hub tt, leave it zeroed.
@@ -1015,12 +1022,14 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        /* stop async schedule right now? */
        if (unlikely (qh == ehci->async)) {
                /* can't get here without STS_ASS set */
-               if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) {
+               if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+                               && !ehci->reclaim) {
+                       /* ... and CMD_IAAD clear */
                        writel (cmd & ~CMD_ASE, &ehci->regs->command);
                        wmb ();
                        // handshake later, if we need to
+                       timer_action_done (ehci, TIMER_ASYNC_OFF);
                }
-               timer_action_done (ehci, TIMER_ASYNC_OFF);
                return;
        } 
 
index ebcca97..5871944 100644 (file)
@@ -707,6 +707,7 @@ iso_stream_init (
        } else {
                u32             addr;
                int             think_time;
+               int             hs_transfers;
 
                addr = dev->ttport << 24;
                if (!ehci_is_TDI(ehci)
@@ -719,6 +720,7 @@ iso_stream_init (
                think_time = dev->tt ? dev->tt->think_time : 0;
                stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
                                dev->speed, is_input, 1, maxp));
+               hs_transfers = max (1u, (maxp + 187) / 188);
                if (is_input) {
                        u32     tmp;
 
@@ -727,12 +729,11 @@ iso_stream_init (
                        stream->usecs = HS_USECS_ISO (1);
                        stream->raw_mask = 1;
 
-                       /* pessimistic c-mask */
-                       tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp)
-                                       / (125 * 1000);
-                       stream->raw_mask |= 3 << (tmp + 9);
+                       /* c-mask as specified in USB 2.0 11.18.4 3.c */
+                       tmp = (1 << (hs_transfers + 2)) - 1;
+                       stream->raw_mask |= tmp << (8 + 2);
                } else
-                       stream->raw_mask = smask_out [maxp / 188];
+                       stream->raw_mask = smask_out [hs_transfers - 1];
                bandwidth = stream->usecs + stream->c_usecs;
                bandwidth /= 1 << (interval + 2);
 
@@ -863,9 +864,8 @@ iso_sched_alloc (unsigned packets, gfp_t mem_flags)
        int                     size = sizeof *iso_sched;
 
        size += packets * sizeof (struct ehci_iso_packet);
-       iso_sched = kmalloc (size, mem_flags);
+       iso_sched = kzalloc(size, mem_flags);
        if (likely (iso_sched != NULL)) {
-               memset(iso_sched, 0, size);
                INIT_LIST_HEAD (&iso_sched->td_list);
        }
        return iso_sched;
@@ -1398,7 +1398,7 @@ itd_complete (
         */
 
        /* give urb back to the driver ... can be out-of-order */
-       dev = usb_get_dev (urb->dev);
+       dev = urb->dev;
        ehci_urb_done (ehci, urb, regs);
        urb = NULL;
 
@@ -1417,7 +1417,6 @@ itd_complete (
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
-       usb_put_dev (dev);
 
        return 1;
 }
@@ -1764,7 +1763,7 @@ sitd_complete (
         */
 
        /* give urb back to the driver */
-       dev = usb_get_dev (urb->dev);
+       dev = urb->dev;
        ehci_urb_done (ehci, urb, regs);
        urb = NULL;
 
@@ -1783,7 +1782,6 @@ sitd_complete (
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
-       usb_put_dev (dev);
 
        return 1;
 }
index 18e257c..679c1cd 100644 (file)
@@ -88,7 +88,12 @@ struct ehci_hcd {                    /* one per controller */
        unsigned long           next_statechange;
        u32                     command;
 
+       /* SILICON QUIRKS */
        unsigned                is_tdi_rh_tt:1; /* TDI roothub with TT */
+       unsigned                no_selective_suspend:1;
+       unsigned                has_fsl_port_bug:1; /* FreeScale */
+
+       u8                      sbrn;           /* packed release number */
 
        /* irq statistics */
 #ifdef EHCI_STATS
@@ -97,7 +102,6 @@ struct ehci_hcd {                    /* one per controller */
 #else
 #      define COUNT(x) do {} while (0)
 #endif
-       u8                      sbrn;           /* packed release number */
 };
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */ 
@@ -638,6 +642,18 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_PPC_83xx
+/* Some Freescale processors have an erratum in which the TT
+ * port number in the queue head was 0..N-1 instead of 1..N.
+ */
+#define        ehci_has_fsl_portno_bug(e)              ((e)->has_fsl_port_bug)
+#else
+#define        ehci_has_fsl_portno_bug(e)              (0)
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
 #ifndef DEBUG
 #define STUB_DEBUG_FILES
 #endif /* DEBUG */
index 641268d..2fe7fd1 100644 (file)
@@ -2137,10 +2137,9 @@ static int etrax_usb_submit_bulk_urb(struct urb *urb)
        urb->status = -EINPROGRESS;
 
        /* Setup the hcpriv data. */
-       urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+       urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
        assert(urb_priv != NULL);
        /* This sets rx_offset to 0. */
-       memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
        urb_priv->urb_state = NOT_STARTED;
        urb->hcpriv = urb_priv;
 
@@ -2475,10 +2474,9 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb)
        urb->status = -EINPROGRESS;
 
        /* Setup the hcpriv data. */
-       urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+       urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
        assert(urb_priv != NULL);
        /* This sets rx_offset to 0. */
-       memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
        urb_priv->urb_state = NOT_STARTED;
        urb->hcpriv = urb_priv;
 
@@ -2767,9 +2765,8 @@ static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
        maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
        interval = urb->interval;
 
-       urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+       urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
        assert(urb_priv != NULL);
-       memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
        urb->hcpriv = urb_priv;
 
        first_ep = &TxIntrEPList[0];
@@ -2997,9 +2994,8 @@ static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
 
        prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
 
-       urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
+       urb_priv = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
        assert(urb_priv != NULL);
-       memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 
        urb->hcpriv = urb_priv;
        urb_priv->epid = epid;
index 972ce04..e99210b 100644 (file)
@@ -724,7 +724,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
                ep = hep->hcpriv;
        else {
                INIT_LIST_HEAD(&ep->schedule);
-               ep->udev = usb_get_dev(udev);
+               ep->udev = udev;
                ep->epnum = epnum;
                ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
                usb_settoggle(udev, epnum, is_out, 0);
@@ -891,7 +891,6 @@ static void isp116x_endpoint_disable(struct usb_hcd *hcd,
        if (!list_empty(&hep->urb_list))
                WARN("ep %p not empty?\n", ep);
 
-       usb_put_dev(ep->udev);
        kfree(ep);
        hep->hcpriv = NULL;
 }
@@ -1553,7 +1552,7 @@ static struct hc_driver isp116x_hc_driver = {
 
 /*----------------------------------------------------------------*/
 
-static int __init_or_module isp116x_remove(struct platform_device *pdev)
+static int isp116x_remove(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
        struct isp116x *isp116x;
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
new file mode 100644 (file)
index 0000000..980030d
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ *  Copyright (C) 2004 SAN People (Pty) Ltd.
+ *  Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * AT91RM9200 Bus Glue
+ *
+ * Based on fragments of 2.4 driver by Rick Bronson.
+ * Based on ohci-omap.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/board.h>
+
+#ifndef CONFIG_ARCH_AT91RM9200
+#error "This file is AT91RM9200 bus glue.  CONFIG_ARCH_AT91RM9200 must be defined."
+#endif
+
+/* interface and function clocks */
+static struct clk *iclk, *fclk;
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void at91_start_hc(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+       struct ohci_regs __iomem *regs = hcd->regs;
+
+       dev_dbg(&pdev->dev, "starting AT91RM9200 OHCI USB Controller\n");
+
+       /*
+        * Start the USB clocks.
+        */
+       clk_enable(iclk);
+       clk_enable(fclk);
+
+       /*
+        * The USB host controller must remain in reset.
+        */
+       writel(0, &regs->control);
+}
+
+static void at91_stop_hc(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+       struct ohci_regs __iomem *regs = hcd->regs;
+
+       dev_dbg(&pdev->dev, "stopping AT91RM9200 OHCI USB Controller\n");
+
+       /*
+        * Put the USB host controller into reset.
+        */
+       writel(0, &regs->control);
+
+       /*
+        * Stop the USB clocks.
+        */
+       clk_disable(fclk);
+       clk_disable(iclk);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_at91_probe - initialize AT91RM9200-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev)
+{
+       int retval;
+       struct usb_hcd *hcd = NULL;
+
+       if (pdev->num_resources != 2) {
+               pr_debug("hcd probe: invalid num_resources");
+               return -ENODEV;
+       }
+
+       if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
+               pr_debug("hcd probe: invalid resource type\n");
+               return -ENODEV;
+       }
+
+       hcd = usb_create_hcd(driver, &pdev->dev, "at91rm9200");
+       if (!hcd)
+               return -ENOMEM;
+       hcd->rsrc_start = pdev->resource[0].start;
+       hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               pr_debug("request_mem_region failed\n");
+               retval = -EBUSY;
+               goto err1;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               pr_debug("ioremap failed\n");
+               retval = -EIO;
+               goto err2;
+       }
+
+       iclk = clk_get(&pdev->dev, "ohci_clk");
+       fclk = clk_get(&pdev->dev, "uhpck");
+
+       at91_start_hc(pdev);
+       ohci_hcd_init(hcd_to_ohci(hcd));
+
+       retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+       if (retval == 0)
+               return retval;
+
+       /* Error handling */
+       at91_stop_hc(pdev);
+
+       clk_put(fclk);
+       clk_put(iclk);
+
+       iounmap(hcd->regs);
+
+ err2:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ err1:
+       usb_put_hcd(hcd);
+       return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_at91_remove - shutdown processing for AT91RM9200-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_at91_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+{
+       usb_remove_hcd(hcd);
+       at91_stop_hc(pdev);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+       clk_put(fclk);
+       clk_put(iclk);
+       fclk = iclk = NULL;
+
+       dev_set_drvdata(&pdev->dev, NULL);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_at91_start (struct usb_hcd *hcd)
+{
+//     struct at91_ohci_data   *board = hcd->self.controller->platform_data;
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       int                     ret;
+
+       if ((ret = ohci_init(ohci)) < 0)
+               return ret;
+
+       if ((ret = ohci_run(ohci)) < 0) {
+               err("can't start %s", hcd->self.bus_name);
+               ohci_stop(hcd);
+               return ret;
+       }
+//     hcd->self.root_hub->maxchild = board->ports;
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_at91_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "AT91RM9200 OHCI",
+       .hcd_priv_size =        sizeof(struct ohci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11 | HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .start =                ohci_at91_start,
+       .stop =                 ohci_stop,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+
+#ifdef CONFIG_PM
+       .hub_suspend =          ohci_hub_suspend,
+       .hub_resume =           ohci_hub_resume,
+#endif
+       .start_port_reset =     ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_at91_drv_probe(struct platform_device *dev)
+{
+       return usb_hcd_at91_probe(&ohci_at91_hc_driver, dev);
+}
+
+static int ohci_hcd_at91_drv_remove(struct platform_device *dev)
+{
+       return usb_hcd_at91_remove(platform_get_drvdata(dev), dev);
+}
+
+#ifdef CONFIG_PM
+static int ohci_hcd_at91_drv_suspend(struct platform_device *dev, u32 state, u32 level)
+{
+       printk("%s(%s:%d): not implemented yet\n",
+               __func__, __FILE__, __LINE__);
+
+       clk_disable(fclk);
+
+       return 0;
+}
+
+static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state)
+{
+       printk("%s(%s:%d): not implemented yet\n",
+               __func__, __FILE__, __LINE__);
+
+       clk_enable(fclk);
+
+       return 0;
+}
+#else
+#define ohci_hcd_at91_drv_suspend NULL
+#define ohci_hcd_at91_drv_resume  NULL
+#endif
+
+static struct platform_driver ohci_hcd_at91_driver = {
+       .probe          = ohci_hcd_at91_drv_probe,
+       .remove         = ohci_hcd_at91_drv_remove,
+       .suspend        = ohci_hcd_at91_drv_suspend,
+       .resume         = ohci_hcd_at91_drv_resume,
+       .driver         = {
+               .name   = "at91rm9200-ohci",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init ohci_hcd_at91_init (void)
+{
+       if (usb_disabled())
+               return -ENODEV;
+
+       return platform_driver_register(&ohci_hcd_at91_driver);
+}
+
+static void __exit ohci_hcd_at91_cleanup (void)
+{
+       platform_driver_unregister(&ohci_hcd_at91_driver);
+}
+
+module_init (ohci_hcd_at91_init);
+module_exit (ohci_hcd_at91_cleanup);
index db280ca..a1c8b3b 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <asm/mach-au1x00/au1000.h>
 
+#ifndef        CONFIG_SOC_AU1200
+
 #define USBH_ENABLE_BE (1<<0)
 #define USBH_ENABLE_C  (1<<1)
 #define USBH_ENABLE_E  (1<<2)
 #error not byte order defined
 #endif
 
+#else   /* Au1200 */
+
+#define USB_HOST_CONFIG    (USB_MSR_BASE + USB_MSR_MCFG)
+#define USB_MCFG_PFEN     (1<<31)
+#define USB_MCFG_RDCOMB   (1<<30)
+#define USB_MCFG_SSDEN    (1<<23)
+#define USB_MCFG_OHCCLKEN (1<<16)
+#define USB_MCFG_UCAM     (1<<7)
+#define USB_MCFG_OBMEN    (1<<1)
+#define USB_MCFG_OMEMEN   (1<<0)
+
+#define USBH_ENABLE_CE    USB_MCFG_OHCCLKEN
+#ifdef CONFIG_DMA_COHERENT
+#define USBH_ENABLE_INIT  (USB_MCFG_OHCCLKEN \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN | USB_MCFG_UCAM \
+                         | USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+#else
+#define USBH_ENABLE_INIT  (USB_MCFG_OHCCLKEN \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN \
+                         | USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+#endif
+#define USBH_DISABLE      (USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+
+#endif  /* Au1200 */
+
 extern int usb_disabled(void);
 
 /*-------------------------------------------------------------------------*/
 
-static void au1xxx_start_hc(struct platform_device *dev)
+static void au1xxx_start_ohc(struct platform_device *dev)
 {
        printk(KERN_DEBUG __FILE__
                ": starting Au1xxx OHCI USB Controller\n");
 
        /* enable host controller */
+
+#ifndef CONFIG_SOC_AU1200
+
        au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
        udelay(1000);
        au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
        udelay(1000);
 
+#else   /* Au1200 */
+
+       /* write HW defaults again in case Yamon cleared them */
+       if (au_readl(USB_HOST_CONFIG) == 0) {
+               au_writel(0x00d02000, USB_HOST_CONFIG);
+               au_readl(USB_HOST_CONFIG);
+               udelay(1000);
+       }
+       au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+       au_readl(USB_HOST_CONFIG);
+       udelay(1000);
+       au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+       au_readl(USB_HOST_CONFIG);
+       udelay(1000);
+
+#endif  /* Au1200 */
+
        /* wait for reset complete (read register twice; see au1500 errata) */
        while (au_readl(USB_HOST_CONFIG),
                !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
@@ -61,13 +110,25 @@ static void au1xxx_start_hc(struct platform_device *dev)
        ": Clock to USB host has been enabled \n");
 }
 
-static void au1xxx_stop_hc(struct platform_device *dev)
+static void au1xxx_stop_ohc(struct platform_device *dev)
 {
        printk(KERN_DEBUG __FILE__
               ": stopping Au1xxx OHCI USB Controller\n");
 
+#ifndef CONFIG_SOC_AU1200
+
        /* Disable clock */
        au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+
+#else   /* Au1200 */
+
+       /* Disable mem */
+       au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+       udelay(1000);
+       /* Disable clock */
+       au_writel(~USBH_ENABLE_CE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+       au_readl(USB_HOST_CONFIG);
+#endif  /* Au1200 */
 }
 
 
@@ -78,7 +139,7 @@ static void au1xxx_stop_hc(struct platform_device *dev)
 
 
 /**
- * usb_hcd_au1xxx_probe - initialize Au1xxx-based HCDs
+ * usb_ohci_au1xxx_probe - initialize Au1xxx-based HCDs
  * Context: !in_interrupt()
  *
  * Allocates basic resources for this USB host controller, and
@@ -86,14 +147,25 @@ static void au1xxx_stop_hc(struct platform_device *dev)
  * through the hotplug entry's driver_data.
  *
  */
-int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
+static int usb_ohci_au1xxx_probe(const struct hc_driver *driver,
                          struct platform_device *dev)
 {
        int retval;
        struct usb_hcd *hcd;
 
-       if(dev->resource[1].flags != IORESOURCE_IRQ) {
-               pr_debug ("resource[1] is not IORESOURCE_IRQ");
+#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
+       /* Au1200 AB USB does not support coherent memory */
+       if (!(read_c0_prid() & 0xff)) {
+               pr_info("%s: this is chip revision AB !!\n",
+                       dev->dev.name);
+               pr_info("%s: update your board or re-configure the kernel\n",
+                       dev->dev.name);
+               return -ENODEV;
+       }
+#endif
+
+       if (dev->resource[1].flags != IORESOURCE_IRQ) {
+               pr_debug("resource[1] is not IORESOURCE_IRQ\n");
                return -ENOMEM;
        }
 
@@ -104,26 +176,26 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
        hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
 
        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               pr_debug("request_mem_region failed");
+               pr_debug("request_mem_region failed\n");
                retval = -EBUSY;
                goto err1;
        }
 
        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
        if (!hcd->regs) {
-               pr_debug("ioremap failed");
+               pr_debug("ioremap failed\n");
                retval = -ENOMEM;
                goto err2;
        }
 
-       au1xxx_start_hc(dev);
+       au1xxx_start_ohc(dev);
        ohci_hcd_init(hcd_to_ohci(hcd));
 
-       retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+       retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
        if (retval == 0)
                return retval;
 
-       au1xxx_stop_hc(dev);
+       au1xxx_stop_ohc(dev);
        iounmap(hcd->regs);
  err2:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
@@ -146,10 +218,10 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
  * context, normally "rmmod", "apmd", or something similar.
  *
  */
-void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
+static void usb_ohci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
 {
        usb_remove_hcd(hcd);
-       au1xxx_stop_hc(dev);
+       au1xxx_stop_ohc(dev);
        iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
@@ -235,7 +307,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
        if (usb_disabled())
                return -ENODEV;
 
-       ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
+       ret = usb_ohci_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
        return ret;
 }
 
@@ -243,7 +315,7 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
-       usb_hcd_au1xxx_remove(hcd, pdev);
+       usb_ohci_au1xxx_remove(hcd, pdev);
        return 0;
 }
        /*TBD*/
index a4b1240..544f758 100644 (file)
@@ -443,11 +443,16 @@ ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
 static int ohci_init (struct ohci_hcd *ohci)
 {
        int ret;
+       struct usb_hcd *hcd = ohci_to_hcd(ohci);
 
        disable (ohci);
-       ohci->regs = ohci_to_hcd(ohci)->regs;
+       ohci->regs = hcd->regs;
        ohci->next_statechange = jiffies;
 
+       /* REVISIT this BIOS handshake is now moved into PCI "quirks", and
+        * was never needed for most non-PCI systems ... remove the code?
+        */
+
 #ifndef IR_DISABLE
        /* SMM owns the HC?  not for long! */
        if (!no_handshake && ohci_readl (ohci,
@@ -478,8 +483,10 @@ static int ohci_init (struct ohci_hcd *ohci)
 
        /* Disable HC interrupts */
        ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-       // flush the writes
-       (void) ohci_readl (ohci, &ohci->regs->control);
+
+       /* flush the writes, and save key bits like RWC */
+       if (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_RWC)
+               ohci->hc_control |= OHCI_CTRL_RWC;
 
        /* Read the number of ports unless overridden */
        if (ohci->num_ports == 0)
@@ -488,16 +495,19 @@ static int ohci_init (struct ohci_hcd *ohci)
        if (ohci->hcca)
                return 0;
 
-       ohci->hcca = dma_alloc_coherent (ohci_to_hcd(ohci)->self.controller,
+       ohci->hcca = dma_alloc_coherent (hcd->self.controller,
                        sizeof *ohci->hcca, &ohci->hcca_dma, 0);
        if (!ohci->hcca)
                return -ENOMEM;
 
        if ((ret = ohci_mem_init (ohci)) < 0)
-               ohci_stop (ohci_to_hcd(ohci));
+               ohci_stop (hcd);
+       else {
+               register_reboot_notifier (&ohci->reboot_notifier);
+               create_debug_files (ohci);
+       }
 
        return ret;
-
 }
 
 /*-------------------------------------------------------------------------*/
@@ -510,6 +520,7 @@ static int ohci_run (struct ohci_hcd *ohci)
 {
        u32                     mask, temp;
        int                     first = ohci->fminterval == 0;
+       struct usb_hcd          *hcd = ohci_to_hcd(ohci);
 
        disable (ohci);
 
@@ -525,18 +536,17 @@ static int ohci_run (struct ohci_hcd *ohci)
                /* also: power/overcurrent flags in roothub.a */
        }
 
-       /* Reset USB nearly "by the book".  RemoteWakeupConnected
-        * saved if boot firmware (BIOS/SMM/...) told us it's connected
-        * (for OHCI integrated on mainboard, it normally is)
+       /* Reset USB nearly "by the book".  RemoteWakeupConnected was
+        * saved if boot firmware (BIOS/SMM/...) told us it's connected,
+        * or if bus glue did the same (e.g. for PCI add-in cards with
+        * PCI PM support).
         */
-       ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
        ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
                        hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-                       ohci->hc_control);
-
-       if (ohci->hc_control & OHCI_CTRL_RWC
-                       && !(ohci->flags & OHCI_QUIRK_AMD756))
-               ohci_to_hcd(ohci)->can_wakeup = 1;
+                       ohci_readl (ohci, &ohci->regs->control));
+       if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
+                       && !device_may_wakeup(hcd->self.controller))
+               device_init_wakeup(hcd->self.controller, 1);
 
        switch (ohci->hc_control & OHCI_CTRL_HCFS) {
        case OHCI_USB_OPER:
@@ -632,7 +642,7 @@ retry:
        ohci->hc_control &= OHCI_CTRL_RWC;
        ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
        ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-       ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+       hcd->state = HC_STATE_RUNNING;
 
        /* wake on ConnectStatusChange, matching external hubs */
        ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
@@ -667,15 +677,10 @@ retry:
 
        // POTPGT delay is bits 24-31, in 2 ms units.
        mdelay ((temp >> 23) & 0x1fe);
-       ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+       hcd->state = HC_STATE_RUNNING;
 
        ohci_dump (ohci, 1);
 
-       if (ohci_to_hcd(ohci)->self.root_hub == NULL) {
-               register_reboot_notifier (&ohci->reboot_notifier);
-               create_debug_files (ohci);
-       }
-
        return 0;
 }
 
@@ -905,6 +910,10 @@ MODULE_LICENSE ("GPL");
 #include "ohci-ppc-soc.c"
 #endif
 
+#ifdef CONFIG_ARCH_AT91RM9200
+#include "ohci-at91.c"
+#endif
+
 #if !(defined(CONFIG_PCI) \
       || defined(CONFIG_SA1111) \
       || defined(CONFIG_ARCH_S3C2410) \
@@ -913,6 +922,7 @@ MODULE_LICENSE ("GPL");
       || defined (CONFIG_PXA27x) \
       || defined (CONFIG_SOC_AU1X00) \
       || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
+      || defined (CONFIG_ARCH_AT91RM9200) \
        )
 #error "missing bus glue for ohci-hcd"
 #endif
index 4b2226d..0bb972b 100644 (file)
@@ -107,7 +107,7 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
                        &ohci->regs->intrstatus);
 
        /* maybe resume can wake root hub */
-       if (hcd->remote_wakeup)
+       if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
                ohci->hc_control |= OHCI_CTRL_RWE;
        else
                ohci->hc_control &= ~OHCI_CTRL_RWE;
@@ -246,9 +246,9 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
        (void) ohci_readl (ohci, &ohci->regs->control);
        msleep (3);
 
-       temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-       if (hcd->can_wakeup)
-               temp |= OHCI_CTRL_RWC;
+       temp = ohci->hc_control;
+       temp &= OHCI_CTRL_RWC;
+       temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
        ohci->hc_control = temp;
        ohci_writel (ohci, temp, &ohci->regs->control);
        (void) ohci_readl (ohci, &ohci->regs->control);
@@ -302,7 +302,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
        int             i, changed = 0, length = 1;
-       int             can_suspend = hcd->can_wakeup;
+       int             can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
        unsigned long   flags;
 
        spin_lock_irqsave (&ohci->lock, flags);
@@ -354,7 +354,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
                 */
                if (!(status & RH_PS_CCS))
                        continue;
-               if ((status & RH_PS_PSS) && hcd->remote_wakeup)
+               if ((status & RH_PS_PSS) && can_suspend)
                        continue;
                can_suspend = 0;
        }
index 3785b3f..ca19abe 100644 (file)
@@ -286,7 +286,7 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
 int usb_hcd_omap_probe (const struct hc_driver *driver,
                          struct platform_device *pdev)
 {
-       int retval;
+       int retval, irq;
        struct usb_hcd *hcd = 0;
        struct ohci_hcd *ohci;
 
@@ -329,7 +329,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
        if (retval < 0)
                goto err2;
 
-       retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT);
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               retval = -ENXIO;
+               goto err2;
+       }
+       retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
        if (retval == 0)
                return retval;
 
index 1b09dde..1bfe96f 100644 (file)
@@ -35,7 +35,10 @@ ohci_pci_start (struct usb_hcd *hcd)
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
        int             ret;
 
-       if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
+       /* REVISIT this whole block should move to reset(), which handles
+        * all the other one-time init.
+        */
+       if (hcd->self.controller) {
                struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
                /* AMD 756, for most chips (early revs), corrupts register
@@ -45,7 +48,8 @@ ohci_pci_start (struct usb_hcd *hcd)
                                && pdev->device == 0x740c) {
                        ohci->flags = OHCI_QUIRK_AMD756;
                        ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-                       // also somewhat erratum 10 (suspend/resume issues)
+                       /* also erratum 10 (suspend/resume issues) */
+                       device_init_wakeup(&hcd->self.root_hub->dev, 0);
                }
 
                /* FIXME for some of the early AMD 760 southbridges, OHCI
@@ -88,6 +92,13 @@ ohci_pci_start (struct usb_hcd *hcd)
                        ohci_dbg (ohci,
                                "enabled Compaq ZFMicro chipset quirk\n");
                }
+
+               /* RWC may not be set for add-in PCI cards, since boot
+                * firmware probably ignored them.  This transfers PCI
+                * PM wakeup capabilities (once the PCI layer is fixed).
+                */
+               if (device_may_wakeup(&pdev->dev))
+                       ohci->hc_control |= OHCI_CTRL_RWC;
        }
 
        /* NOTE: there may have already been a first reset, to
index 517360b..a923430 100644 (file)
@@ -853,7 +853,7 @@ static int sl811h_urb_enqueue(
 
        } else {
                INIT_LIST_HEAD(&ep->schedule);
-               ep->udev = usb_get_dev(udev);
+               ep->udev = udev;
                ep->epnum = epnum;
                ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
                ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE;
@@ -1052,7 +1052,6 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
        if (!list_empty(&hep->urb_list))
                WARN("ep %p not empty?\n", ep);
 
-       usb_put_dev(ep->udev);
        kfree(ep);
        hep->hcpriv = NULL;
 }
index 5832953..e123931 100644 (file)
 
 #include "uhci-hcd.h"
 
-static struct dentry *uhci_debugfs_root = NULL;
+#define uhci_debug_operations (* (struct file_operations *) NULL)
+static struct dentry *uhci_debugfs_root;
+
+#ifdef DEBUG
 
 /* Handle REALLY large printks so we don't overflow buffers */
-static inline void lprintk(char *buf)
+static void lprintk(char *buf)
 {
        char *p;
 
@@ -90,13 +93,59 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
        return out - buf;
 }
 
-static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
+static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
 {
        char *out = buf;
-       struct urb_priv *urbp;
-       struct list_head *head, *tmp;
        struct uhci_td *td;
-       int i = 0, checked = 0, prevactive = 0;
+       int i, nactive, ninactive;
+
+       if (len < 200)
+               return 0;
+
+       out += sprintf(out, "urb_priv [%p] ", urbp);
+       out += sprintf(out, "urb [%p] ", urbp->urb);
+       out += sprintf(out, "qh [%p] ", urbp->qh);
+       out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
+       out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
+                       (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
+
+       switch (usb_pipetype(urbp->urb->pipe)) {
+       case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break;
+       case PIPE_INTERRUPT: out += sprintf(out, "INT"); break;
+       case PIPE_BULK: out += sprintf(out, "BLK"); break;
+       case PIPE_CONTROL: out += sprintf(out, "CTL"); break;
+       }
+
+       out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : ""));
+
+       if (urbp->urb->status != -EINPROGRESS)
+               out += sprintf(out, " Status=%d", urbp->urb->status);
+       out += sprintf(out, "\n");
+
+       i = nactive = ninactive = 0;
+       list_for_each_entry(td, &urbp->td_list, list) {
+               if (++i <= 10 || debug > 2) {
+                       out += sprintf(out, "%*s%d: ", space + 2, "", i);
+                       out += uhci_show_td(td, out, len - (out - buf), 0);
+               } else {
+                       if (td_status(td) & TD_CTRL_ACTIVE)
+                               ++nactive;
+                       else
+                               ++ninactive;
+               }
+       }
+       if (nactive + ninactive > 0)
+               out += sprintf(out, "%*s[skipped %d inactive and %d active "
+                               "TDs]\n",
+                               space, "", ninactive, nactive);
+
+       return out - buf;
+}
+
+static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
+{
+       char *out = buf;
+       int i, nurbs;
        __le32 element = qh_element(qh);
 
        /* Try to make sure there's enough memory */
@@ -118,86 +167,40 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
        if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
                out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
 
-       if (!qh->urbp) {
-               out += sprintf(out, "%*s  urbp == NULL\n", space, "");
-               goto out;
-       }
-
-       urbp = qh->urbp;
-
-       head = &urbp->td_list;
-       tmp = head->next;
-
-       td = list_entry(tmp, struct uhci_td, list);
-
-       if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
-               out += sprintf(out, "%*s Element != First TD\n", space, "");
-
-       while (tmp != head) {
-               struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-               tmp = tmp->next;
-
-               out += sprintf(out, "%*s%d: ", space + 2, "", i++);
-               out += uhci_show_td(td, out, len - (out - buf), 0);
-
-               if (i > 10 && !checked && prevactive && tmp != head &&
-                   debug <= 2) {
-                       struct list_head *ntmp = tmp;
-                       struct uhci_td *ntd = td;
-                       int active = 1, ni = i;
-
-                       checked = 1;
-
-                       while (ntmp != head && ntmp->next != head && active) {
-                               ntd = list_entry(ntmp, struct uhci_td, list);
-
-                               ntmp = ntmp->next;
-
-                               active = td_status(ntd) & TD_CTRL_ACTIVE;
-
-                               ni++;
-                       }
-
-                       if (active && ni > i) {
-                               out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i);
-                               tmp = ntmp;
-                               td = ntd;
-                               i = ni;
-                       }
+       if (list_empty(&qh->queue)) {
+               out += sprintf(out, "%*s  queue is empty\n", space, "");
+       } else {
+               struct urb_priv *urbp = list_entry(qh->queue.next,
+                               struct urb_priv, node);
+               struct uhci_td *td = list_entry(urbp->td_list.next,
+                               struct uhci_td, list);
+
+               if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
+                       out += sprintf(out, "%*s Element != First TD\n",
+                                       space, "");
+               i = nurbs = 0;
+               list_for_each_entry(urbp, &qh->queue, node) {
+                       if (++i <= 10)
+                               out += uhci_show_urbp(urbp, out,
+                                               len - (out - buf), space + 2);
+                       else
+                               ++nurbs;
                }
-
-               prevactive = td_status(td) & TD_CTRL_ACTIVE;
+               if (nurbs > 0)
+                       out += sprintf(out, "%*s Skipped %d URBs\n",
+                                       space, "", nurbs);
        }
 
-       if (list_empty(&urbp->queue_list) || urbp->queued)
-               goto out;
-
-       out += sprintf(out, "%*sQueued QHs:\n", -space, "--");
-
-       head = &urbp->queue_list;
-       tmp = head->next;
-
-       while (tmp != head) {
-               struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
-                                               queue_list);
-               tmp = tmp->next;
-
-               out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
+       if (qh->udev) {
+               out += sprintf(out, "%*s  Dummy TD\n", space, "");
+               out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
        }
 
-out:
        return out - buf;
 }
 
-#define show_frame_num()       \
-       if (!shown) {           \
-         shown = 1;            \
-         out += sprintf(out, "- Frame %d\n", i); \
-       }
-
-#ifdef CONFIG_PROC_FS
 static const char * const qh_names[] = {
+  "skel_unlink_qh", "skel_iso_qh",
   "skel_int128_qh", "skel_int64_qh",
   "skel_int32_qh", "skel_int16_qh",
   "skel_int8_qh", "skel_int4_qh",
@@ -206,12 +209,6 @@ static const char * const qh_names[] = {
   "skel_bulk_qh", "skel_term_qh"
 };
 
-#define show_qh_name()         \
-       if (!shown) {           \
-         shown = 1;            \
-         out += sprintf(out, "- %s\n", qh_names[i]); \
-       }
-
 static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
 {
        char *out = buf;
@@ -321,139 +318,29 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
        return out - buf;
 }
 
-static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len)
-{
-       struct list_head *tmp;
-       char *out = buf;
-       int count = 0;
-
-       if (len < 200)
-               return 0;
-
-       out += sprintf(out, "urb_priv [%p] ", urbp);
-       out += sprintf(out, "urb [%p] ", urbp->urb);
-       out += sprintf(out, "qh [%p] ", urbp->qh);
-       out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
-       out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
-
-       switch (usb_pipetype(urbp->urb->pipe)) {
-       case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break;
-       case PIPE_INTERRUPT: out += sprintf(out, "INT "); break;
-       case PIPE_BULK: out += sprintf(out, "BLK "); break;
-       case PIPE_CONTROL: out += sprintf(out, "CTL "); break;
-       }
-
-       out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : ""));
-       out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
-
-       if (urbp->urb->status != -EINPROGRESS)
-               out += sprintf(out, "Status=%d ", urbp->urb->status);
-       //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
-
-       count = 0;
-       list_for_each(tmp, &urbp->td_list)
-               count++;
-       out += sprintf(out, "TDs=%d ",count);
-
-       if (urbp->queued)
-               out += sprintf(out, "queued\n");
-       else {
-               count = 0;
-               list_for_each(tmp, &urbp->queue_list)
-                       count++;
-               out += sprintf(out, "queued URBs=%d\n", count);
-       }
-
-       return out - buf;
-}
-
-static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
-{
-       char *out = buf;
-       struct list_head *head, *tmp;
-       int count;
-
-       out += sprintf(out, "Main list URBs:");
-       if (list_empty(&uhci->urb_list))
-               out += sprintf(out, " Empty\n");
-       else {
-               out += sprintf(out, "\n");
-               count = 0;
-               head = &uhci->urb_list;
-               tmp = head->next;
-               while (tmp != head) {
-                       struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-                       out += sprintf(out, "  %d: ", ++count);
-                       out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-                       tmp = tmp->next;
-               }
-       }
-
-       out += sprintf(out, "Remove list URBs:");
-       if (list_empty(&uhci->urb_remove_list))
-               out += sprintf(out, " Empty\n");
-       else {
-               out += sprintf(out, "\n");
-               count = 0;
-               head = &uhci->urb_remove_list;
-               tmp = head->next;
-               while (tmp != head) {
-                       struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-                       out += sprintf(out, "  %d: ", ++count);
-                       out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-                       tmp = tmp->next;
-               }
-       }
-
-       out += sprintf(out, "Complete list URBs:");
-       if (list_empty(&uhci->complete_list))
-               out += sprintf(out, " Empty\n");
-       else {
-               out += sprintf(out, "\n");
-               count = 0;
-               head = &uhci->complete_list;
-               tmp = head->next;
-               while (tmp != head) {
-                       struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-                       out += sprintf(out, "  %d: ", ++count);
-                       out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-                       tmp = tmp->next;
-               }
-       }
-
-       return out - buf;
-}
-
 static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 {
-       unsigned long flags;
        char *out = buf;
        int i, j;
        struct uhci_qh *qh;
        struct uhci_td *td;
        struct list_head *tmp, *head;
 
-       spin_lock_irqsave(&uhci->lock, flags);
-
        out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
        out += sprintf(out, "HC status\n");
        out += uhci_show_status(uhci, out, len - (out - buf));
+       if (debug <= 1)
+               return out - buf;
 
        out += sprintf(out, "Frame List\n");
        for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-               int shown = 0;
                td = uhci->frame_cpu[i];
                if (!td)
                        continue;
 
-               if (td->dma_handle != (dma_addr_t)uhci->frame[i]) {
-                       show_frame_num();
+               out += sprintf(out, "- Frame %d\n", i); \
+               if (td->dma_handle != (dma_addr_t)uhci->frame[i])
                        out += sprintf(out, "    frame list does not match td->dma_handle!\n");
-               }
-               show_frame_num();
 
                head = &td->fl_list;
                tmp = head;
@@ -467,14 +354,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
        out += sprintf(out, "Skeleton QHs\n");
 
        for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
-               int shown = 0;
+               int cnt = 0;
 
                qh = uhci->skelqh[i];
-
-               if (debug > 1) {
-                       show_qh_name();
-                       out += uhci_show_qh(qh, out, len - (out - buf), 4);
-               }
+               out += sprintf(out, "- %s\n", qh_names[i]); \
+               out += uhci_show_qh(qh, out, len - (out - buf), 4);
 
                /* Last QH is the Terminating QH, it's different */
                if (i == UHCI_NUM_SKELQH - 1) {
@@ -487,53 +371,37 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
                        continue;
                }
 
-               j = (i < 7) ? 7 : i+1;          /* Next skeleton */
-               if (list_empty(&qh->list)) {
-                       if (i < UHCI_NUM_SKELQH - 1) {
-                               if (qh->link !=
-                                   (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
-                                       show_qh_name();
-                                       out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
-                               }
-                       }
-
-                       continue;
-               }
-
-               show_qh_name();
-
-               head = &qh->list;
+               j = (i < 9) ? 9 : i+1;          /* Next skeleton */
+               head = &qh->node;
                tmp = head->next;
 
                while (tmp != head) {
-                       qh = list_entry(tmp, struct uhci_qh, list);
-
+                       qh = list_entry(tmp, struct uhci_qh, node);
                        tmp = tmp->next;
-
-                       out += uhci_show_qh(qh, out, len - (out - buf), 4);
+                       if (++cnt <= 10)
+                               out += uhci_show_qh(qh, out,
+                                               len - (out - buf), 4);
                }
+               if ((cnt -= 10) > 0)
+                       out += sprintf(out, "    Skipped %d QHs\n", cnt);
 
-               if (i < UHCI_NUM_SKELQH - 1) {
+               if (i > 1 && i < UHCI_NUM_SKELQH - 1) {
                        if (qh->link !=
                            (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
                                out += sprintf(out, "    last QH not linked to next skeleton!\n");
                }
        }
 
-       if (debug > 2)
-               out += uhci_show_lists(uhci, out, len - (out - buf));
-
-       spin_unlock_irqrestore(&uhci->lock, flags);
-
        return out - buf;
 }
 
+#ifdef CONFIG_DEBUG_FS
+
 #define MAX_OUTPUT     (64 * 1024)
 
 struct uhci_debug {
        int size;
        char *data;
-       struct uhci_hcd *uhci;
 };
 
 static int uhci_debug_open(struct inode *inode, struct file *file)
@@ -541,6 +409,7 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
        struct uhci_hcd *uhci = inode->u.generic_ip;
        struct uhci_debug *up;
        int ret = -ENOMEM;
+       unsigned long flags;
 
        lock_kernel();
        up = kmalloc(sizeof(*up), GFP_KERNEL);
@@ -553,7 +422,11 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
                goto out;
        }
 
-       up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+       up->size = 0;
+       spin_lock_irqsave(&uhci->lock, flags);
+       if (uhci->is_initialized)
+               up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+       spin_unlock_irqrestore(&uhci->lock, flags);
 
        file->private_data = up;
 
@@ -604,15 +477,32 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+#undef uhci_debug_operations
 static struct file_operations uhci_debug_operations = {
+       .owner =        THIS_MODULE,
        .open =         uhci_debug_open,
        .llseek =       uhci_debug_lseek,
        .read =         uhci_debug_read,
        .release =      uhci_debug_release,
 };
 
-#else  /* CONFIG_DEBUG_FS */
+#endif /* CONFIG_DEBUG_FS */
 
-#define uhci_debug_operations (* (struct file_operations *) NULL)
+#else  /* DEBUG */
+
+static inline void lprintk(char *buf)
+{}
+
+static inline int uhci_show_qh(struct uhci_qh *qh, char *buf,
+               int len, int space)
+{
+       return 0;
+}
+
+static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
+               char *buf, int len)
+{
+       return 0;
+}
 
 #endif
index dfe121d..4edb833 100644 (file)
@@ -54,7 +54,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v3.0"
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
 Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
 Alan Stern"
@@ -68,12 +68,16 @@ Alan Stern"
  * debug = 3, show all TDs in URBs when dumping
  */
 #ifdef DEBUG
+#define DEBUG_CONFIGURED       1
 static int debug = 1;
-#else
-static int debug = 0;
-#endif
 module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug level");
+
+#else
+#define DEBUG_CONFIGURED       0
+#define debug                  0
+#endif
+
 static char *errbuf;
 #define ERRBUF_LEN    (32 * 1024)
 
@@ -338,6 +342,12 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
                                dev_err(uhci_dev(uhci),
                                        "host controller halted, "
                                        "very bad!\n");
+                               if (debug > 1 && errbuf) {
+                                       /* Print the schedule for debugging */
+                                       uhci_sprint_schedule(uhci,
+                                                       errbuf, ERRBUF_LEN);
+                                       lprintk(errbuf);
+                               }
                                hc_died(uhci);
 
                                /* Force a callback in case there are
@@ -376,6 +386,14 @@ static void release_uhci(struct uhci_hcd *uhci)
 {
        int i;
 
+       if (DEBUG_CONFIGURED) {
+               spin_lock_irq(&uhci->lock);
+               uhci->is_initialized = 0;
+               spin_unlock_irq(&uhci->lock);
+
+               debugfs_remove(uhci->dentry);
+       }
+
        for (i = 0; i < UHCI_NUM_SKELQH; i++)
                uhci_free_qh(uhci, uhci->skelqh[i]);
 
@@ -390,8 +408,6 @@ static void release_uhci(struct uhci_hcd *uhci)
        dma_free_coherent(uhci_dev(uhci),
                        UHCI_NUMFRAMES * sizeof(*uhci->frame),
                        uhci->frame, uhci->frame_dma_handle);
-
-       debugfs_remove(uhci->dentry);
 }
 
 static int uhci_reset(struct usb_hcd *hcd)
@@ -474,33 +490,29 @@ static int uhci_start(struct usb_hcd *hcd)
 
        hcd->uses_new_polling = 1;
 
-       dentry = debugfs_create_file(hcd->self.bus_name,
-                       S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
-                       &uhci_debug_operations);
-       if (!dentry) {
-               dev_err(uhci_dev(uhci),
-                               "couldn't create uhci debugfs entry\n");
-               retval = -ENOMEM;
-               goto err_create_debug_entry;
-       }
-       uhci->dentry = dentry;
-
        uhci->fsbr = 0;
        uhci->fsbrtimeout = 0;
 
        spin_lock_init(&uhci->lock);
-       INIT_LIST_HEAD(&uhci->qh_remove_list);
 
        INIT_LIST_HEAD(&uhci->td_remove_list);
-
-       INIT_LIST_HEAD(&uhci->urb_remove_list);
-
-       INIT_LIST_HEAD(&uhci->urb_list);
-
-       INIT_LIST_HEAD(&uhci->complete_list);
+       INIT_LIST_HEAD(&uhci->idle_qh_list);
 
        init_waitqueue_head(&uhci->waitqh);
 
+       if (DEBUG_CONFIGURED) {
+               dentry = debugfs_create_file(hcd->self.bus_name,
+                               S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
+                               uhci, &uhci_debug_operations);
+               if (!dentry) {
+                       dev_err(uhci_dev(uhci), "couldn't create uhci "
+                                       "debugfs entry\n");
+                       retval = -ENOMEM;
+                       goto err_create_debug_entry;
+               }
+               uhci->dentry = dentry;
+       }
+
        uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
                        UHCI_NUMFRAMES * sizeof(*uhci->frame),
                        &uhci->frame_dma_handle, 0);
@@ -540,7 +552,7 @@ static int uhci_start(struct usb_hcd *hcd)
        }
 
        for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-               uhci->skelqh[i] = uhci_alloc_qh(uhci);
+               uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL);
                if (!uhci->skelqh[i]) {
                        dev_err(uhci_dev(uhci), "unable to allocate QH\n");
                        goto err_alloc_skelqh;
@@ -557,13 +569,17 @@ static int uhci_start(struct usb_hcd *hcd)
                        uhci->skel_int16_qh->link =
                        uhci->skel_int8_qh->link =
                        uhci->skel_int4_qh->link =
-                       uhci->skel_int2_qh->link =
-                       cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
-       uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
-
-       uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
-       uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH;
-       uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH;
+                       uhci->skel_int2_qh->link = UHCI_PTR_QH |
+                       cpu_to_le32(uhci->skel_int1_qh->dma_handle);
+
+       uhci->skel_int1_qh->link = UHCI_PTR_QH |
+                       cpu_to_le32(uhci->skel_ls_control_qh->dma_handle);
+       uhci->skel_ls_control_qh->link = UHCI_PTR_QH |
+                       cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
+       uhci->skel_fs_control_qh->link = UHCI_PTR_QH |
+                       cpu_to_le32(uhci->skel_bulk_qh->dma_handle);
+       uhci->skel_bulk_qh->link = UHCI_PTR_QH |
+                       cpu_to_le32(uhci->skel_term_qh->dma_handle);
 
        /* This dummy TD is to work around a bug in Intel PIIX controllers */
        uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
@@ -589,15 +605,15 @@ static int uhci_start(struct usb_hcd *hcd)
 
                /*
                 * ffs (Find First bit Set) does exactly what we need:
-                * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[6],
-                * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
-                * ffs > 6 => not on any high-period queue, so use
-                *      skel_int1_qh = skelqh[7].
+                * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
+                * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+                * ffs >= 7 => not on any high-period queue, so use
+                *      skel_int1_qh = skelqh[9].
                 * Add UHCI_NUMFRAMES to insure at least one bit is set.
                 */
-               irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
-               if (irq < 0)
-                       irq = 7;
+               irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
+               if (irq <= 1)
+                       irq = 9;
 
                /* Only place we don't use the frame list routines */
                uhci->frame[i] = UHCI_PTR_QH |
@@ -611,6 +627,7 @@ static int uhci_start(struct usb_hcd *hcd)
        mb();
 
        configure_hc(uhci);
+       uhci->is_initialized = 1;
        start_rh(uhci);
        return 0;
 
@@ -767,13 +784,30 @@ static int uhci_resume(struct usb_hcd *hcd)
 }
 #endif
 
-/* Wait until all the URBs for a particular device/endpoint are gone */
+/* Wait until a particular device/endpoint's QH is idle, and free it */
 static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
-               struct usb_host_endpoint *ep)
+               struct usb_host_endpoint *hep)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       struct uhci_qh *qh;
+
+       spin_lock_irq(&uhci->lock);
+       qh = (struct uhci_qh *) hep->hcpriv;
+       if (qh == NULL)
+               goto done;
+
+       while (qh->state != QH_STATE_IDLE) {
+               ++uhci->num_waiting;
+               spin_unlock_irq(&uhci->lock);
+               wait_event_interruptible(uhci->waitqh,
+                               qh->state == QH_STATE_IDLE);
+               spin_lock_irq(&uhci->lock);
+               --uhci->num_waiting;
+       }
 
-       wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list));
+       uhci_free_qh(uhci, qh);
+done:
+       spin_unlock_irq(&uhci->lock);
 }
 
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
@@ -857,16 +891,15 @@ static int __init uhci_hcd_init(void)
        if (usb_disabled())
                return -ENODEV;
 
-       if (debug) {
+       if (DEBUG_CONFIGURED) {
                errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
                if (!errbuf)
                        goto errbuf_failed;
+               uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
+               if (!uhci_debugfs_root)
+                       goto debug_failed;
        }
 
-       uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
-       if (!uhci_debugfs_root)
-               goto debug_failed;
-
        uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
                sizeof(struct urb_priv), 0, 0, NULL, NULL);
        if (!uhci_up_cachep)
index 8b4b887..4a69c7e 100644 (file)
@@ -28,8 +28,9 @@
 #define   USBSTS_USBINT                0x0001  /* Interrupt due to IOC */
 #define   USBSTS_ERROR         0x0002  /* Interrupt due to error */
 #define   USBSTS_RD            0x0004  /* Resume Detect */
-#define   USBSTS_HSE           0x0008  /* Host System Error - basically PCI problems */
-#define   USBSTS_HCPE          0x0010  /* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HSE           0x0008  /* Host System Error: PCI problems */
+#define   USBSTS_HCPE          0x0010  /* Host Controller Process Error:
+                                        * the schedule is buggy */
 #define   USBSTS_HCH           0x0020  /* HC Halted */
 
 /* Interrupt enable register */
@@ -47,7 +48,8 @@
 /* USB port status and control registers */
 #define USBPORTSC1     16
 #define USBPORTSC2     18
-#define   USBPORTSC_CCS                0x0001  /* Current Connect Status ("device present") */
+#define   USBPORTSC_CCS                0x0001  /* Current Connect Status
+                                        * ("device present") */
 #define   USBPORTSC_CSC                0x0002  /* Connect Status Change */
 #define   USBPORTSC_PE         0x0004  /* Port Enable */
 #define   USBPORTSC_PEC                0x0008  /* Port Enable Change */
 #define   USBLEGSUP_RWC                0x8f00  /* the R/WC bits */
 #define   USBLEGSUP_RO         0x5040  /* R/O and reserved bits */
 
-#define UHCI_PTR_BITS          cpu_to_le32(0x000F)
-#define UHCI_PTR_TERM          cpu_to_le32(0x0001)
-#define UHCI_PTR_QH            cpu_to_le32(0x0002)
-#define UHCI_PTR_DEPTH         cpu_to_le32(0x0004)
-#define UHCI_PTR_BREADTH       cpu_to_le32(0x0000)
+#define UHCI_PTR_BITS          __constant_cpu_to_le32(0x000F)
+#define UHCI_PTR_TERM          __constant_cpu_to_le32(0x0001)
+#define UHCI_PTR_QH            __constant_cpu_to_le32(0x0002)
+#define UHCI_PTR_DEPTH         __constant_cpu_to_le32(0x0004)
+#define UHCI_PTR_BREADTH       __constant_cpu_to_le32(0x0000)
 
 #define UHCI_NUMFRAMES         1024    /* in the frame list [array] */
 #define UHCI_MAX_SOF_NUMBER    2047    /* in an SOF packet */
-#define CAN_SCHEDULE_FRAMES    1000    /* how far future frames can be scheduled */
+#define CAN_SCHEDULE_FRAMES    1000    /* how far in the future frames
+                                        * can be scheduled */
 
 
 /*
  */
 
 /*
- * One role of a QH is to hold a queue of TDs for some endpoint.  Each QH is
- * used with one URB, and qh->element (updated by the HC) is either:
- *   - the next unprocessed TD for the URB, or
- *   - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or
- *   - the QH for the next URB queued to the same endpoint.
+ * One role of a QH is to hold a queue of TDs for some endpoint.  One QH goes
+ * with each endpoint, and qh->element (updated by the HC) is either:
+ *   - the next unprocessed TD in the endpoint's queue, or
+ *   - UHCI_PTR_TERM (when there's no more traffic for this endpoint).
  *
  * The other role of a QH is to serve as a "skeleton" framelist entry, so we
  * can easily splice a QH for some endpoint into the schedule at the right
  * place.  Then qh->element is UHCI_PTR_TERM.
  *
- * In the frame list, qh->link maintains a list of QHs seen by the HC:
+ * In the schedule, qh->link maintains a list of QHs seen by the HC:
  *     skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
+ *
+ * qh->node is the software equivalent of qh->link.  The differences
+ * are that the software list is doubly-linked and QHs in the UNLINKING
+ * state are on the software list but not the hardware schedule.
+ *
+ * For bookkeeping purposes we maintain QHs even for Isochronous endpoints,
+ * but they never get added to the hardware schedule.
  */
+#define QH_STATE_IDLE          1       /* QH is not being used */
+#define QH_STATE_UNLINKING     2       /* QH has been removed from the
+                                        * schedule but the hardware may
+                                        * still be using it */
+#define QH_STATE_ACTIVE                3       /* QH is on the schedule */
+
 struct uhci_qh {
        /* Hardware fields */
-       __le32 link;                    /* Next queue */
-       __le32 element;                 /* Queue element pointer */
+       __le32 link;                    /* Next QH in the schedule */
+       __le32 element;                 /* Queue element (TD) pointer */
 
        /* Software fields */
        dma_addr_t dma_handle;
 
-       struct urb_priv *urbp;
+       struct list_head node;          /* Node in the list of QHs */
+       struct usb_host_endpoint *hep;  /* Endpoint information */
+       struct usb_device *udev;
+       struct list_head queue;         /* Queue of urbps for this QH */
+       struct uhci_qh *skel;           /* Skeleton for this QH */
+       struct uhci_td *dummy_td;       /* Dummy TD to end the queue */
 
-       struct list_head list;
-       struct list_head remove_list;
+       unsigned int unlink_frame;      /* When the QH was unlinked */
+       int state;                      /* QH_STATE_xxx; see above */
+
+       unsigned int initial_toggle:1;  /* Endpoint's current toggle value */
+       unsigned int needs_fixup:1;     /* Must fix the TD toggle values */
+       unsigned int is_stopped:1;      /* Queue was stopped by an error */
 } __attribute__((aligned(16)));
 
 /*
  * We need a special accessor for the element pointer because it is
  * subject to asynchronous updates by the controller.
  */
-static __le32 inline qh_element(struct uhci_qh *qh) {
+static inline __le32 qh_element(struct uhci_qh *qh) {
        __le32 element = qh->element;
 
        barrier();
@@ -149,11 +173,13 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
 #define TD_CTRL_ACTLEN_MASK    0x7FF   /* actual length, encoded as n - 1 */
 
 #define TD_CTRL_ANY_ERROR      (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
-                                TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+                                TD_CTRL_BABBLE | TD_CTRL_CRCTIME | \
+                                TD_CTRL_BITSTUFF)
 
 #define uhci_maxerr(err)               ((err) << TD_CTRL_C_ERR_SHIFT)
 #define uhci_status_bits(ctrl_sts)     ((ctrl_sts) & 0xF60000)
-#define uhci_actual_length(ctrl_sts)   (((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+#define uhci_actual_length(ctrl_sts)   (((ctrl_sts) + 1) & \
+                       TD_CTRL_ACTLEN_MASK)    /* 1-based */
 
 /*
  * for TD <info>: (a.k.a. Token)
@@ -163,7 +189,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
 #define TD_TOKEN_TOGGLE_SHIFT  19
 #define TD_TOKEN_TOGGLE                (1 << 19)
 #define TD_TOKEN_EXPLEN_SHIFT  21
-#define TD_TOKEN_EXPLEN_MASK   0x7FF           /* expected length, encoded as n - 1 */
+#define TD_TOKEN_EXPLEN_MASK   0x7FF   /* expected length, encoded as n-1 */
 #define TD_TOKEN_PID_MASK      0xFF
 
 #define uhci_explen(len)       ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
@@ -187,7 +213,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
  * sw space after the TD entry.
  *
  * td->link points to either another TD (not necessarily for the same urb or
- * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs).
+ * even the same endpoint), or nothing (PTR_TERM), or a QH.
  */
 struct uhci_td {
        /* Hardware fields */
@@ -210,7 +236,7 @@ struct uhci_td {
  * We need a special accessor for the control/status word because it is
  * subject to asynchronous updates by the controller.
  */
-static u32 inline td_status(struct uhci_td *td) {
+static inline u32 td_status(struct uhci_td *td) {
        __le32 status = td->status;
 
        barrier();
@@ -223,17 +249,14 @@ static u32 inline td_status(struct uhci_td *td) {
  */
 
 /*
- * The UHCI driver places Interrupt, Control and Bulk into QHs both
- * to group together TDs for one transfer, and also to facilitate queuing
- * of URBs. To make it easy to insert entries into the schedule, we have
- * a skeleton of QHs for each predefined Interrupt latency, low-speed
- * control, full-speed control and terminating QH (see explanation for
- * the terminating QH below).
+ * The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for
+ * automatic queuing. To make it easy to insert entries into the schedule,
+ * we have a skeleton of QHs for each predefined Interrupt latency,
+ * low-speed control, full-speed control, bulk, and terminating QH
+ * (see explanation for the terminating QH below).
  *
  * When we want to add a new QH, we add it to the end of the list for the
- * skeleton QH.
- *
- * For instance, the queue can look like this:
+ * skeleton QH.  For instance, the schedule list can look like this:
  *
  * skel int128 QH
  * dev 1 interrupt QH
@@ -256,26 +279,31 @@ static u32 inline td_status(struct uhci_td *td) {
  * - To loop back to the full-speed control queue for full-speed bandwidth
  *   reclamation.
  *
- * Isochronous transfers are stored before the start of the skeleton
- * schedule and don't use QHs. While the UHCI spec doesn't forbid the
- * use of QHs for Isochronous, it doesn't use them either. And the spec
- * says that queues never advance on an error completion status, which
- * makes them totally unsuitable for Isochronous transfers.
+ * There's a special skeleton QH for Isochronous QHs.  It never appears
+ * on the schedule, and Isochronous TDs go on the schedule before the
+ * the skeleton QHs.  The hardware accesses them directly rather than
+ * through their QH, which is used only for bookkeeping purposes.
+ * While the UHCI spec doesn't forbid the use of QHs for Isochronous,
+ * it doesn't use them either.  And the spec says that queues never
+ * advance on an error completion status, which makes them totally
+ * unsuitable for Isochronous transfers.
  */
 
-#define UHCI_NUM_SKELQH                12
-#define skel_int128_qh         skelqh[0]
-#define skel_int64_qh          skelqh[1]
-#define skel_int32_qh          skelqh[2]
-#define skel_int16_qh          skelqh[3]
-#define skel_int8_qh           skelqh[4]
-#define skel_int4_qh           skelqh[5]
-#define skel_int2_qh           skelqh[6]
-#define skel_int1_qh           skelqh[7]
-#define skel_ls_control_qh     skelqh[8]
-#define skel_fs_control_qh     skelqh[9]
-#define skel_bulk_qh           skelqh[10]
-#define skel_term_qh           skelqh[11]
+#define UHCI_NUM_SKELQH                14
+#define skel_unlink_qh         skelqh[0]
+#define skel_iso_qh            skelqh[1]
+#define skel_int128_qh         skelqh[2]
+#define skel_int64_qh          skelqh[3]
+#define skel_int32_qh          skelqh[4]
+#define skel_int16_qh          skelqh[5]
+#define skel_int8_qh           skelqh[6]
+#define skel_int4_qh           skelqh[7]
+#define skel_int2_qh           skelqh[8]
+#define skel_int1_qh           skelqh[9]
+#define skel_ls_control_qh     skelqh[10]
+#define skel_fs_control_qh     skelqh[11]
+#define skel_bulk_qh           skelqh[12]
+#define skel_term_qh           skelqh[13]
 
 /*
  * Search tree for determining where <interval> fits in the skelqh[]
@@ -293,21 +321,21 @@ static inline int __interval_to_skel(int interval)
        if (interval < 16) {
                if (interval < 4) {
                        if (interval < 2)
-                               return 7;       /* int1 for 0-1 ms */
-                       return 6;               /* int2 for 2-3 ms */
+                               return 9;       /* int1 for 0-1 ms */
+                       return 8;               /* int2 for 2-3 ms */
                }
                if (interval < 8)
-                       return 5;               /* int4 for 4-7 ms */
-               return 4;                       /* int8 for 8-15 ms */
+                       return 7;               /* int4 for 4-7 ms */
+               return 6;                       /* int8 for 8-15 ms */
        }
        if (interval < 64) {
                if (interval < 32)
-                       return 3;               /* int16 for 16-31 ms */
-               return 2;                       /* int32 for 32-63 ms */
+                       return 5;               /* int16 for 16-31 ms */
+               return 4;                       /* int32 for 32-63 ms */
        }
        if (interval < 128)
-               return 1;                       /* int64 for 64-127 ms */
-       return 0;                               /* int128 for 128-255 ms (Max.) */
+               return 3;                       /* int64 for 64-127 ms */
+       return 2;                               /* int128 for 128-255 ms (Max.) */
 }
 
 
@@ -360,15 +388,16 @@ struct uhci_hcd {
 
        struct uhci_td *term_td;        /* Terminating TD, see UHCI bug */
        struct uhci_qh *skelqh[UHCI_NUM_SKELQH];        /* Skeleton QHs */
+       struct uhci_qh *next_qh;        /* Next QH to scan */
 
        spinlock_t lock;
 
-       dma_addr_t frame_dma_handle;            /* Hardware frame list */
+       dma_addr_t frame_dma_handle;    /* Hardware frame list */
        __le32 *frame;
-       void **frame_cpu;                       /* CPU's frame list */
+       void **frame_cpu;               /* CPU's frame list */
 
-       int fsbr;                               /* Full-speed bandwidth reclamation */
-       unsigned long fsbrtimeout;              /* FSBR delay */
+       int fsbr;                       /* Full-speed bandwidth reclamation */
+       unsigned long fsbrtimeout;      /* FSBR delay */
 
        enum uhci_rh_state rh_state;
        unsigned long auto_stop_time;           /* When to AUTO_STOP */
@@ -382,6 +411,7 @@ struct uhci_hcd {
        unsigned int hc_inaccessible:1;         /* HC is suspended or dead */
        unsigned int working_RD:1;              /* Suspended root hub doesn't
                                                   need to be polled */
+       unsigned int is_initialized:1;          /* Data structure is usable */
 
        /* Support for port suspend/resume/reset */
        unsigned long port_c_suspend;           /* Bit-arrays of ports */
@@ -389,27 +419,16 @@ struct uhci_hcd {
        unsigned long resuming_ports;
        unsigned long ports_timeout;            /* Time to stop signalling */
 
-       /* Main list of URBs currently controlled by this HC */
-       struct list_head urb_list;
-
-       /* List of QHs that are done, but waiting to be unlinked (race) */
-       struct list_head qh_remove_list;
-       unsigned int qh_remove_age;             /* Age in frames */
-
        /* List of TDs that are done, but waiting to be freed (race) */
        struct list_head td_remove_list;
        unsigned int td_remove_age;             /* Age in frames */
 
-       /* List of asynchronously unlinked URBs */
-       struct list_head urb_remove_list;
-       unsigned int urb_remove_age;            /* Age in frames */
-
-       /* List of URBs awaiting completion callback */
-       struct list_head complete_list;
+       struct list_head idle_qh_list;          /* Where the idle QHs live */
 
        int rh_numports;                        /* Number of root-hub ports */
 
        wait_queue_head_t waitqh;               /* endpoint_disable waiters */
+       int num_waiting;                        /* Number of waiters */
 };
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
@@ -429,7 +448,7 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
  *     Private per-URB data
  */
 struct urb_priv {
-       struct list_head urb_list;
+       struct list_head node;          /* Node in the QH's urbp list */
 
        struct urb *urb;
 
@@ -437,15 +456,8 @@ struct urb_priv {
        struct list_head td_list;
 
        unsigned fsbr : 1;              /* URB turned on FSBR */
-       unsigned fsbr_timeout : 1;      /* URB timed out on FSBR */
-       unsigned queued : 1;            /* QH was queued (not linked in) */
-       unsigned short_control_packet : 1;      /* If we get a short packet during */
-                                               /*  a control transfer, retrigger */
-                                               /*  the status phase */
-
-       unsigned long fsbrtime;         /* In jiffies */
-
-       struct list_head queue_list;
+       unsigned short_transfer : 1;    /* URB got a short transfer, no
+                                        * need to rescan */
 };
 
 
index a71e48a..152971d 100644 (file)
@@ -99,6 +99,21 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
        }
 }
 
+/* Wait for the UHCI controller in HP's iLO2 server management chip.
+ * It can take up to 250 us to finish a reset and set the CSC bit.
+ */
+static void wait_for_HP(unsigned long port_addr)
+{
+       int i;
+
+       for (i = 10; i < 250; i += 10) {
+               if (inw(port_addr) & USBPORTSC_CSC)
+                       return;
+               udelay(10);
+       }
+       /* Log a warning? */
+}
+
 static void uhci_check_ports(struct uhci_hcd *uhci)
 {
        unsigned int port;
@@ -113,6 +128,12 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
                                CLR_RH_PORTSTAT(USBPORTSC_PR);
                                udelay(10);
 
+                               /* HP's server management chip requires
+                                * a longer delay. */
+                               if (to_pci_dev(uhci_dev(uhci))->vendor ==
+                                               PCI_VENDOR_ID_HP)
+                                       wait_for_HP(port_addr);
+
                                /* If the port was enabled before, turning
                                 * reset on caused a port enable change.
                                 * Turning reset off causes a port connect
index 7823980..a06d84c 100644 (file)
  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
  */
 
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
-static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
 static void uhci_free_pending_tds(struct uhci_hcd *uhci);
 
 /*
@@ -30,7 +26,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
  * games with the FSBR code to make sure we get the correct order in all
  * the cases. I don't think it's worth the effort
  */
-static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
+static void uhci_set_next_interrupt(struct uhci_hcd *uhci)
 {
        if (uhci->is_stopped)
                mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
@@ -42,12 +38,6 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
        uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
 }
 
-static inline void uhci_moveto_complete(struct uhci_hcd *uhci, 
-                                       struct urb_priv *urbp)
-{
-       list_move_tail(&urbp->urb_list, &uhci->complete_list);
-}
-
 static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
 {
        dma_addr_t dma_handle;
@@ -58,10 +48,6 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
                return NULL;
 
        td->dma_handle = dma_handle;
-
-       td->link = UHCI_PTR_TERM;
-       td->buffer = 0;
-
        td->frame = -1;
 
        INIT_LIST_HEAD(&td->list);
@@ -71,6 +57,18 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
        return td;
 }
 
+static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
+{
+       if (!list_empty(&td->list))
+               dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
+       if (!list_empty(&td->remove_list))
+               dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
+       if (!list_empty(&td->fl_list))
+               dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
+
+       dma_pool_free(uhci->td_pool, td, td->dma_handle);
+}
+
 static inline void uhci_fill_td(struct uhci_td *td, u32 status,
                u32 token, u32 buffer)
 {
@@ -82,7 +80,8 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status,
 /*
  * We insert Isochronous URBs directly into the frame list at the beginning
  */
-static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
+static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
+               struct uhci_td *td, unsigned framenum)
 {
        framenum &= (UHCI_NUMFRAMES - 1);
 
@@ -108,7 +107,7 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
        }
 }
 
-static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci,
+static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
                struct uhci_td *td)
 {
        /* If it's not inserted, don't remove it */
@@ -139,48 +138,21 @@ static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci,
        td->frame = -1;
 }
 
-static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
+/*
+ * Remove all the TDs for an Isochronous URB from the frame list
+ */
+static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
 {
        struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
        struct uhci_td *td;
 
        list_for_each_entry(td, &urbp->td_list, list)
-               uhci_remove_td_frame_list(uhci, td);
+               uhci_remove_td_from_frame_list(uhci, td);
        wmb();
 }
 
-/*
- * Inserts a td list into qh.
- */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       struct uhci_td *td;
-       __le32 *plink;
-
-       /* Ordering isn't important here yet since the QH hasn't been */
-       /* inserted into the schedule yet */
-       plink = &qh->element;
-       list_for_each_entry(td, &urbp->td_list, list) {
-               *plink = cpu_to_le32(td->dma_handle) | breadth;
-               plink = &td->link;
-       }
-       *plink = UHCI_PTR_TERM;
-}
-
-static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
-{
-       if (!list_empty(&td->list))
-               dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
-       if (!list_empty(&td->remove_list))
-               dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
-       if (!list_empty(&td->fl_list))
-               dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
-
-       dma_pool_free(uhci->td_pool, td, td->dma_handle);
-}
-
-static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci)
+static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
+               struct usb_device *udev, struct usb_host_endpoint *hep)
 {
        dma_addr_t dma_handle;
        struct uhci_qh *qh;
@@ -194,256 +166,217 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci)
        qh->element = UHCI_PTR_TERM;
        qh->link = UHCI_PTR_TERM;
 
-       qh->urbp = NULL;
-
-       INIT_LIST_HEAD(&qh->list);
-       INIT_LIST_HEAD(&qh->remove_list);
+       INIT_LIST_HEAD(&qh->queue);
+       INIT_LIST_HEAD(&qh->node);
 
+       if (udev) {             /* Normal QH */
+               qh->dummy_td = uhci_alloc_td(uhci);
+               if (!qh->dummy_td) {
+                       dma_pool_free(uhci->qh_pool, qh, dma_handle);
+                       return NULL;
+               }
+               qh->state = QH_STATE_IDLE;
+               qh->hep = hep;
+               qh->udev = udev;
+               hep->hcpriv = qh;
+
+       } else {                /* Skeleton QH */
+               qh->state = QH_STATE_ACTIVE;
+               qh->udev = NULL;
+       }
        return qh;
 }
 
 static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-       if (!list_empty(&qh->list))
+       WARN_ON(qh->state != QH_STATE_IDLE && qh->udev);
+       if (!list_empty(&qh->queue))
                dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
-       if (!list_empty(&qh->remove_list))
-               dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
 
+       list_del(&qh->node);
+       if (qh->udev) {
+               qh->hep->hcpriv = NULL;
+               uhci_free_td(uhci, qh->dummy_td);
+       }
        dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
 /*
- * Append this urb's qh after the last qh in skelqh->list
- *
- * Note that urb_priv.queue_list doesn't have a separate queue head;
- * it's a ring with every element "live".
+ * When the currently executing URB is dequeued, save its current toggle value
  */
-static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
+static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb)
 {
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       struct urb_priv *turbp;
-       struct uhci_qh *lqh;
+       struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+       struct uhci_td *td;
 
-       /* Grab the last QH */
-       lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
+       /* If the QH element pointer is UHCI_PTR_TERM then then currently
+        * executing URB has already been unlinked, so this one isn't it. */
+       if (qh_element(qh) == UHCI_PTR_TERM ||
+                               qh->queue.next != &urbp->node)
+               return;
+       qh->element = UHCI_PTR_TERM;
 
-       /* Point to the next skelqh */
-       urbp->qh->link = lqh->link;
-       wmb();                          /* Ordering is important */
+       /* Only bulk and interrupt pipes have to worry about toggles */
+       if (!(usb_pipetype(urb->pipe) == PIPE_BULK ||
+                       usb_pipetype(urb->pipe) == PIPE_INTERRUPT))
+               return;
 
-       /*
-        * Patch QHs for previous endpoint's queued URBs?  HC goes
-        * here next, not to the next skelqh it now points to.
-        *
-        *    lqh --> td ... --> qh ... --> td --> qh ... --> td
-        *     |                 |                 |
-        *     v                 v                 v
-        *     +<----------------+-----------------+
-        *     v
-        *    newqh --> td ... --> td
-        *     |
-        *     v
-        *    ...
-        *
-        * The HC could see (and use!) any of these as we write them.
-        */
-       lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
-       if (lqh->urbp) {
-               list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list)
-                       turbp->qh->link = lqh->link;
+       /* Find the first active TD; that's the device's toggle state */
+       list_for_each_entry(td, &urbp->td_list, list) {
+               if (td_status(td) & TD_CTRL_ACTIVE) {
+                       qh->needs_fixup = 1;
+                       qh->initial_toggle = uhci_toggle(td_token(td));
+                       return;
+               }
        }
 
-       list_add_tail(&urbp->qh->list, &skelqh->list);
+       WARN_ON(1);
 }
 
 /*
- * Start removal of QH from schedule; it finishes next frame.
- * TDs should be unlinked before this is called.
+ * Fix up the data toggles for URBs in a queue, when one of them
+ * terminates early (short transfer, error, or dequeued).
  */
-static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
 {
-       struct uhci_qh *pqh;
-       __le32 newlink;
-
-       if (!qh)
-               return;
-
-       /*
-        * Only go through the hoops if it's actually linked in
-        */
-       if (!list_empty(&qh->list)) {
-
-               /* If our queue is nonempty, make the next URB the head */
-               if (!list_empty(&qh->urbp->queue_list)) {
-                       struct urb_priv *nurbp;
-
-                       nurbp = list_entry(qh->urbp->queue_list.next,
-                                       struct urb_priv, queue_list);
-                       nurbp->queued = 0;
-                       list_add(&nurbp->qh->list, &qh->list);
-                       newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
-               } else
-                       newlink = qh->link;
-
-               /* Fix up the previous QH's queue to link to either
-                * the new head of this queue or the start of the
-                * next endpoint's queue. */
-               pqh = list_entry(qh->list.prev, struct uhci_qh, list);
-               pqh->link = newlink;
-               if (pqh->urbp) {
-                       struct urb_priv *turbp;
-
-                       list_for_each_entry(turbp, &pqh->urbp->queue_list,
-                                       queue_list)
-                               turbp->qh->link = newlink;
+       struct urb_priv *urbp = NULL;
+       struct uhci_td *td;
+       unsigned int toggle = qh->initial_toggle;
+       unsigned int pipe;
+
+       /* Fixups for a short transfer start with the second URB in the
+        * queue (the short URB is the first). */
+       if (skip_first)
+               urbp = list_entry(qh->queue.next, struct urb_priv, node);
+
+       /* When starting with the first URB, if the QH element pointer is
+        * still valid then we know the URB's toggles are okay. */
+       else if (qh_element(qh) != UHCI_PTR_TERM)
+               toggle = 2;
+
+       /* Fix up the toggle for the URBs in the queue.  Normally this
+        * loop won't run more than once: When an error or short transfer
+        * occurs, the queue usually gets emptied. */
+       urbp = list_prepare_entry(urbp, &qh->queue, node);
+       list_for_each_entry_continue(urbp, &qh->queue, node) {
+
+               /* If the first TD has the right toggle value, we don't
+                * need to change any toggles in this URB */
+               td = list_entry(urbp->td_list.next, struct uhci_td, list);
+               if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) {
+                       td = list_entry(urbp->td_list.next, struct uhci_td,
+                                       list);
+                       toggle = uhci_toggle(td_token(td)) ^ 1;
+
+               /* Otherwise all the toggles in the URB have to be switched */
+               } else {
+                       list_for_each_entry(td, &urbp->td_list, list) {
+                               td->token ^= __constant_cpu_to_le32(
+                                                       TD_TOKEN_TOGGLE);
+                               toggle ^= 1;
+                       }
                }
-               wmb();
-
-               /* Leave qh->link in case the HC is on the QH now, it will */
-               /* continue the rest of the schedule */
-               qh->element = UHCI_PTR_TERM;
-
-               list_del_init(&qh->list);
-       }
-
-       list_del_init(&qh->urbp->queue_list);
-       qh->urbp = NULL;
-
-       uhci_get_current_frame_number(uhci);
-       if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) {
-               uhci_free_pending_qhs(uhci);
-               uhci->qh_remove_age = uhci->frame_number;
        }
 
-       /* Check to see if the remove list is empty. Set the IOC bit */
-       /* to force an interrupt so we can remove the QH */
-       if (list_empty(&uhci->qh_remove_list))
-               uhci_set_next_interrupt(uhci);
-
-       list_add(&qh->remove_list, &uhci->qh_remove_list);
+       wmb();
+       pipe = list_entry(qh->queue.next, struct urb_priv, node)->urb->pipe;
+       usb_settoggle(qh->udev, usb_pipeendpoint(pipe),
+                       usb_pipeout(pipe), toggle);
+       qh->needs_fixup = 0;
 }
 
-static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+/*
+ * Put a QH on the schedule in both hardware and software
+ */
+static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       struct uhci_td *td;
-
-       list_for_each_entry(td, &urbp->td_list, list) {
-               if (toggle)
-                       td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
-               else
-                       td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
-
-               toggle ^= 1;
-       }
-
-       return toggle;
-}
+       struct uhci_qh *pqh;
 
-/* This function will append one URB's QH to another URB's QH. This is for */
-/* queuing interrupt, control or bulk transfers */
-static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
-{
-       struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
-       struct uhci_td *lltd;
+       WARN_ON(list_empty(&qh->queue));
 
-       eurbp = eurb->hcpriv;
-       urbp = urb->hcpriv;
+       /* Set the element pointer if it isn't set already.
+        * This isn't needed for Isochronous queues, but it doesn't hurt. */
+       if (qh_element(qh) == UHCI_PTR_TERM) {
+               struct urb_priv *urbp = list_entry(qh->queue.next,
+                               struct urb_priv, node);
+               struct uhci_td *td = list_entry(urbp->td_list.next,
+                               struct uhci_td, list);
 
-       /* Find the first URB in the queue */
-       furbp = eurbp;
-       if (eurbp->queued) {
-               list_for_each_entry(furbp, &eurbp->queue_list, queue_list)
-                       if (!furbp->queued)
-                               break;
+               qh->element = cpu_to_le32(td->dma_handle);
        }
 
-       lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
-
-       lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-
-       /* Control transfers always start with toggle 0 */
-       if (!usb_pipecontrol(urb->pipe))
-               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                               usb_pipeout(urb->pipe),
-                               uhci_fixup_toggle(urb,
-                                       uhci_toggle(td_token(lltd)) ^ 1));
-
-       /* All qhs in the queue need to link to the next queue */
-       urbp->qh->link = eurbp->qh->link;
-
-       wmb();                  /* Make sure we flush everything */
-
-       lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
-
-       list_add_tail(&urbp->queue_list, &furbp->queue_list);
-
-       urbp->queued = 1;
+       if (qh->state == QH_STATE_ACTIVE)
+               return;
+       qh->state = QH_STATE_ACTIVE;
+
+       /* Move the QH from its old list to the end of the appropriate
+        * skeleton's list */
+       if (qh == uhci->next_qh)
+               uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
+                               node);
+       list_move_tail(&qh->node, &qh->skel->node);
+
+       /* Link it into the schedule */
+       pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+       qh->link = pqh->link;
+       wmb();
+       pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle);
 }
 
-static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
+/*
+ * Take a QH off the hardware schedule
+ */
+static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-       struct urb_priv *urbp, *nurbp, *purbp, *turbp;
-       struct uhci_td *pltd;
-       unsigned int toggle;
-
-       urbp = urb->hcpriv;
+       struct uhci_qh *pqh;
 
-       if (list_empty(&urbp->queue_list))
+       if (qh->state == QH_STATE_UNLINKING)
                return;
+       WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev);
+       qh->state = QH_STATE_UNLINKING;
 
-       nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
+       /* Unlink the QH from the schedule and record when we did it */
+       pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+       pqh->link = qh->link;
+       mb();
 
-       /*
-        * Fix up the toggle for the following URBs in the queue.
-        * Only needed for bulk and interrupt: control and isochronous
-        * endpoints don't propagate toggles between messages.
-        */
-       if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
-               if (!urbp->queued)
-                       /* We just set the toggle in uhci_unlink_generic */
-                       toggle = usb_gettoggle(urb->dev,
-                                       usb_pipeendpoint(urb->pipe),
-                                       usb_pipeout(urb->pipe));
-               else {
-                       /* If we're in the middle of the queue, grab the */
-                       /* toggle from the TD previous to us */
-                       purbp = list_entry(urbp->queue_list.prev,
-                                       struct urb_priv, queue_list);
-                       pltd = list_entry(purbp->td_list.prev,
-                                       struct uhci_td, list);
-                       toggle = uhci_toggle(td_token(pltd)) ^ 1;
-               }
+       uhci_get_current_frame_number(uhci);
+       qh->unlink_frame = uhci->frame_number;
 
-               list_for_each_entry(turbp, &urbp->queue_list, queue_list) {
-                       if (!turbp->queued)
-                               break;
-                       toggle = uhci_fixup_toggle(turbp->urb, toggle);
-               }
+       /* Force an interrupt so we know when the QH is fully unlinked */
+       if (list_empty(&uhci->skel_unlink_qh->node))
+               uhci_set_next_interrupt(uhci);
 
-               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                               usb_pipeout(urb->pipe), toggle);
-       }
+       /* Move the QH from its old list to the end of the unlinking list */
+       if (qh == uhci->next_qh)
+               uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
+                               node);
+       list_move_tail(&qh->node, &uhci->skel_unlink_qh->node);
+}
 
-       if (urbp->queued) {
-               /* We're somewhere in the middle (or end).  The case where
-                * we're at the head is handled in uhci_remove_qh(). */
-               purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
-                               queue_list);
+/*
+ * When we and the controller are through with a QH, it becomes IDLE.
+ * This happens when a QH has been off the schedule (on the unlinking
+ * list) for more than one frame, or when an error occurs while adding
+ * the first URB onto a new QH.
+ */
+static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       WARN_ON(qh->state == QH_STATE_ACTIVE);
 
-               pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-               if (nurbp->queued)
-                       pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
-               else
-                       /* The next URB happens to be the beginning, so */
-                       /*  we're the last, end the chain */
-                       pltd->link = UHCI_PTR_TERM;
-       }
+       if (qh == uhci->next_qh)
+               uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
+                               node);
+       list_move(&qh->node, &uhci->idle_qh_list);
+       qh->state = QH_STATE_IDLE;
 
-       /* urbp->queue_list is handled in uhci_remove_qh() */
+       /* If anyone is waiting for a QH to become idle, wake them up */
+       if (uhci->num_waiting)
+               wake_up_all(&uhci->waitqh);
 }
 
-static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
+               struct urb *urb)
 {
        struct urb_priv *urbp;
 
@@ -453,16 +386,11 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u
 
        memset((void *)urbp, 0, sizeof(*urbp));
 
-       urbp->fsbrtime = jiffies;
        urbp->urb = urb;
+       urb->hcpriv = urbp;
        
+       INIT_LIST_HEAD(&urbp->node);
        INIT_LIST_HEAD(&urbp->td_list);
-       INIT_LIST_HEAD(&urbp->queue_list);
-       INIT_LIST_HEAD(&urbp->urb_list);
-
-       list_add_tail(&urbp->urb_list, &uhci->urb_list);
-
-       urb->hcpriv = urbp;
 
        return urbp;
 }
@@ -482,18 +410,14 @@ static void uhci_remove_td_from_urb(struct uhci_td *td)
        list_del_init(&td->list);
 }
 
-static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
+static void uhci_free_urb_priv(struct uhci_hcd *uhci,
+               struct urb_priv *urbp)
 {
        struct uhci_td *td, *tmp;
-       struct urb_priv *urbp;
-
-       urbp = (struct urb_priv *)urb->hcpriv;
-       if (!urbp)
-               return;
 
-       if (!list_empty(&urbp->urb_list))
-               dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
-                               "or uhci->remove_list!\n", urb);
+       if (!list_empty(&urbp->node))
+               dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
+                               urbp->urb);
 
        uhci_get_current_frame_number(uhci);
        if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
@@ -502,7 +426,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
        }
 
        /* Check to see if the remove list is empty. Set the IOC bit */
-       /* to force an interrupt so we can remove the TDs*/
+       /* to force an interrupt so we can remove the TDs*/
        if (list_empty(&uhci->td_remove_list))
                uhci_set_next_interrupt(uhci);
 
@@ -511,7 +435,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
                list_add(&td->remove_list, &uhci->td_remove_list);
        }
 
-       urb->hcpriv = NULL;
+       urbp->urb->hcpriv = NULL;
        kmem_cache_free(uhci_up_cachep, urbp);
 }
 
@@ -570,34 +494,33 @@ static int uhci_map_status(int status, int dir_out)
 /*
  * Control transfers
  */
-static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
+               struct uhci_qh *qh)
 {
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
        struct uhci_td *td;
-       struct uhci_qh *qh, *skelqh;
        unsigned long destination, status;
-       int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+       int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
        int len = urb->transfer_buffer_length;
        dma_addr_t data = urb->transfer_dma;
+       __le32 *plink;
 
        /* The "pipe" thing contains the destination in bits 8--18 */
        destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
 
-       /* 3 errors */
-       status = TD_CTRL_ACTIVE | uhci_maxerr(3);
+       /* 3 errors, dummy TD remains inactive */
+       status = uhci_maxerr(3);
        if (urb->dev->speed == USB_SPEED_LOW)
                status |= TD_CTRL_LS;
 
        /*
         * Build the TD for the control request setup packet
         */
-       td = uhci_alloc_td(uhci);
-       if (!td)
-               return -ENOMEM;
-
+       td = qh->dummy_td;
        uhci_add_td_to_urb(urb, td);
        uhci_fill_td(td, status, destination | uhci_explen(8),
-               urb->setup_dma);
+                       urb->setup_dma);
+       plink = &td->link;
+       status |= TD_CTRL_ACTIVE;
 
        /*
         * If direction is "send", change the packet ID from SETUP (0x2D)
@@ -615,21 +538,20 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
         * Build the DATA TDs
         */
        while (len > 0) {
-               int pktsze = len;
-
-               if (pktsze > maxsze)
-                       pktsze = maxsze;
+               int pktsze = min(len, maxsze);
 
                td = uhci_alloc_td(uhci);
                if (!td)
-                       return -ENOMEM;
+                       goto nomem;
+               *plink = cpu_to_le32(td->dma_handle);
 
                /* Alternate Data0/1 (start with Data1) */
                destination ^= TD_TOKEN_TOGGLE;
        
                uhci_add_td_to_urb(urb, td);
                uhci_fill_td(td, status, destination | uhci_explen(pktsze),
-                       data);
+                               data);
+               plink = &td->link;
 
                data += pktsze;
                len -= pktsze;
@@ -640,7 +562,8 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
         */
        td = uhci_alloc_td(uhci);
        if (!td)
-               return -ENOMEM;
+               goto nomem;
+       *plink = cpu_to_le32(td->dma_handle);
 
        /*
         * It's IN if the pipe is an output pipe or we're not expecting
@@ -658,16 +581,21 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
 
        uhci_add_td_to_urb(urb, td);
        uhci_fill_td(td, status | TD_CTRL_IOC,
-               destination | uhci_explen(0), 0);
-
-       qh = uhci_alloc_qh(uhci);
-       if (!qh)
-               return -ENOMEM;
+                       destination | uhci_explen(0), 0);
+       plink = &td->link;
 
-       urbp->qh = qh;
-       qh->urbp = urbp;
+       /*
+        * Build the new dummy TD and activate the old one
+        */
+       td = uhci_alloc_td(uhci);
+       if (!td)
+               goto nomem;
+       *plink = cpu_to_le32(td->dma_handle);
 
-       uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+       uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
+       wmb();
+       qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
+       qh->dummy_td = td;
 
        /* Low-speed transfers get a different queue, and won't hog the bus.
         * Also, some devices enumerate better without FSBR; the easiest way
@@ -675,18 +603,17 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
         * isn't in the CONFIGURED state. */
        if (urb->dev->speed == USB_SPEED_LOW ||
                        urb->dev->state != USB_STATE_CONFIGURED)
-               skelqh = uhci->skel_ls_control_qh;
+               qh->skel = uhci->skel_ls_control_qh;
        else {
-               skelqh = uhci->skel_fs_control_qh;
+               qh->skel = uhci->skel_fs_control_qh;
                uhci_inc_fsbr(uhci, urb);
        }
+       return 0;
 
-       if (eurb)
-               uhci_append_queued_urb(uhci, eurb, urb);
-       else
-               uhci_insert_qh(uhci, skelqh, urb);
-
-       return -EINPROGRESS;
+nomem:
+       /* Remove the dummy TD from the td_list so it doesn't get freed */
+       uhci_remove_td_from_urb(qh->dummy_td);
+       return -ENOMEM;
 }
 
 /*
@@ -703,7 +630,7 @@ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
        struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
        struct uhci_td *td;
 
-       urbp->short_control_packet = 1;
+       urbp->short_transfer = 1;
 
        td = list_entry(urbp->td_list.prev, struct uhci_td, list);
        urbp->qh->element = cpu_to_le32(td->dma_handle);
@@ -720,16 +647,14 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
        unsigned int status;
        int ret = 0;
 
-       if (list_empty(&urbp->td_list))
-               return -EINVAL;
-
        head = &urbp->td_list;
-
-       if (urbp->short_control_packet) {
+       if (urbp->short_transfer) {
                tmp = head->prev;
                goto status_stage;
        }
 
+       urb->actual_length = 0;
+
        tmp = head->next;
        td = list_entry(tmp, struct uhci_td, list);
 
@@ -742,8 +667,6 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
        if (status)
                goto td_error;
 
-       urb->actual_length = 0;
-
        /* The rest of the TDs (but the last) are data */
        tmp = tmp->next;
        while (tmp != head && tmp->next != head) {
@@ -770,10 +693,7 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
                                goto err;
                        }
 
-                       if (uhci_packetid(td_token(td)) == USB_PID_IN)
-                               return usb_control_retrigger_status(uhci, urb);
-                       else
-                               return 0;
+                       return usb_control_retrigger_status(uhci, urb);
                }
        }
 
@@ -814,34 +734,40 @@ err:
                if (errbuf) {
                        /* Print the chain for debugging purposes */
                        uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
                        lprintk(errbuf);
                }
        }
 
+       /* Note that the queue has stopped */
+       urbp->qh->element = UHCI_PTR_TERM;
+       urbp->qh->is_stopped = 1;
        return ret;
 }
 
 /*
  * Common submit for bulk and interrupt
  */
-static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
+static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
+               struct uhci_qh *qh)
 {
        struct uhci_td *td;
-       struct uhci_qh *qh;
        unsigned long destination, status;
-       int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+       int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
        int len = urb->transfer_buffer_length;
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
        dma_addr_t data = urb->transfer_dma;
+       __le32 *plink;
+       unsigned int toggle;
 
        if (len < 0)
                return -EINVAL;
 
        /* The "pipe" thing contains the destination in bits 8--18 */
        destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+       toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                        usb_pipeout(urb->pipe));
 
-       status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
+       /* 3 errors, dummy TD remains inactive */
+       status = uhci_maxerr(3);
        if (urb->dev->speed == USB_SPEED_LOW)
                status |= TD_CTRL_LS;
        if (usb_pipein(urb->pipe))
@@ -850,30 +776,34 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
        /*
         * Build the DATA TDs
         */
+       plink = NULL;
+       td = qh->dummy_td;
        do {    /* Allow zero length packets */
                int pktsze = maxsze;
 
-               if (pktsze >= len) {
+               if (len <= pktsze) {            /* The last packet */
                        pktsze = len;
                        if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
                                status &= ~TD_CTRL_SPD;
                }
 
-               td = uhci_alloc_td(uhci);
-               if (!td)
-                       return -ENOMEM;
-
+               if (plink) {
+                       td = uhci_alloc_td(uhci);
+                       if (!td)
+                               goto nomem;
+                       *plink = cpu_to_le32(td->dma_handle);
+               }
                uhci_add_td_to_urb(urb, td);
-               uhci_fill_td(td, status, destination | uhci_explen(pktsze) |
-                       (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                        usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-                       data);
+               uhci_fill_td(td, status,
+                               destination | uhci_explen(pktsze) |
+                                       (toggle << TD_TOKEN_TOGGLE_SHIFT),
+                               data);
+               plink = &td->link;
+               status |= TD_CTRL_ACTIVE;
 
                data += pktsze;
                len -= maxsze;
-
-               usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                       usb_pipeout(urb->pipe));
+               toggle ^= 1;
        } while (len > 0);
 
        /*
@@ -883,20 +813,22 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
         * however, if transfer_length == 0, the zero packet was already
         * prepared above.
         */
-       if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
-           !len && urb->transfer_buffer_length) {
+       if ((urb->transfer_flags & URB_ZERO_PACKET) &&
+                       usb_pipeout(urb->pipe) && len == 0 &&
+                       urb->transfer_buffer_length > 0) {
                td = uhci_alloc_td(uhci);
                if (!td)
-                       return -ENOMEM;
+                       goto nomem;
+               *plink = cpu_to_le32(td->dma_handle);
 
                uhci_add_td_to_urb(urb, td);
-               uhci_fill_td(td, status, destination | uhci_explen(0) |
-                       (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                        usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-                       data);
+               uhci_fill_td(td, status,
+                               destination | uhci_explen(0) |
+                                       (toggle << TD_TOKEN_TOGGLE_SHIFT),
+                               data);
+               plink = &td->link;
 
-               usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-                       usb_pipeout(urb->pipe));
+               toggle ^= 1;
        }
 
        /* Set the interrupt-on-completion flag on the last packet.
@@ -905,24 +837,29 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
         * fast side but not enough to justify delaying an interrupt
         * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
         * flag setting. */
-       td->status |= cpu_to_le32(TD_CTRL_IOC);
+       td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
-       qh = uhci_alloc_qh(uhci);
-       if (!qh)
-               return -ENOMEM;
-
-       urbp->qh = qh;
-       qh->urbp = urbp;
+       /*
+        * Build the new dummy TD and activate the old one
+        */
+       td = uhci_alloc_td(uhci);
+       if (!td)
+               goto nomem;
+       *plink = cpu_to_le32(td->dma_handle);
 
-       /* Always breadth first */
-       uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
+       uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
+       wmb();
+       qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
+       qh->dummy_td = td;
 
-       if (eurb)
-               uhci_append_queued_urb(uhci, eurb, urb);
-       else
-               uhci_insert_qh(uhci, skelqh, urb);
+       usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                       usb_pipeout(urb->pipe), toggle);
+       return 0;
 
-       return -EINPROGRESS;
+nomem:
+       /* Remove the dummy TD from the td_list so it doesn't get freed */
+       uhci_remove_td_from_urb(qh->dummy_td);
+       return -ENOMEM;
 }
 
 /*
@@ -954,8 +891,27 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
                        if (urb->transfer_flags & URB_SHORT_NOT_OK) {
                                ret = -EREMOTEIO;
                                goto err;
-                       } else
-                               return 0;
+                       }
+
+                       /*
+                        * This URB stopped short of its end.  We have to
+                        * fix up the toggles of the following URBs on the
+                        * queue and restart the queue.
+                        *
+                        * Do this only the first time we encounter the
+                        * short URB.
+                        */
+                       if (!urbp->short_transfer) {
+                               urbp->short_transfer = 1;
+                               urbp->qh->initial_toggle =
+                                               uhci_toggle(td_token(td)) ^ 1;
+                               uhci_fixup_toggles(urbp->qh, 1);
+
+                               td = list_entry(urbp->td_list.prev,
+                                               struct uhci_td, list);
+                               urbp->qh->element = td->link;
+                       }
+                       break;
                }
        }
 
@@ -964,31 +920,30 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
 td_error:
        ret = uhci_map_status(status, uhci_packetout(td_token(td)));
 
-err:
-       /* 
-        * Enable this chunk of code if you want to see some more debugging.
-        * But be careful, it has the tendancy to starve out khubd and prevent
-        * disconnects from happening successfully if you have a slow debug
-        * log interface (like a serial console.
-        */
-#if 0
        if ((debug == 1 && ret != -EPIPE) || debug > 1) {
                /* Some debugging code */
                dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
                                __FUNCTION__, status);
 
-               if (errbuf) {
+               if (debug > 1 && errbuf) {
                        /* Print the chain for debugging purposes */
                        uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
                        lprintk(errbuf);
                }
        }
-#endif
+err:
+
+       /* Note that the queue has stopped and save the next toggle value */
+       urbp->qh->element = UHCI_PTR_TERM;
+       urbp->qh->is_stopped = 1;
+       urbp->qh->needs_fixup = 1;
+       urbp->qh->initial_toggle = uhci_toggle(td_token(td)) ^
+                       (ret == -EREMOTEIO);
        return ret;
 }
 
-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
+               struct uhci_qh *qh)
 {
        int ret;
 
@@ -996,95 +951,60 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struc
        if (urb->dev->speed == USB_SPEED_LOW)
                return -EINVAL;
 
-       ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
-       if (ret == -EINPROGRESS)
+       qh->skel = uhci->skel_bulk_qh;
+       ret = uhci_submit_common(uhci, urb, qh);
+       if (ret == 0)
                uhci_inc_fsbr(uhci, urb);
-
        return ret;
 }
 
-static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
+static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
+               struct uhci_qh *qh)
 {
-       /* USB 1.1 interrupt transfers only involve one packet per interval;
-        * that's the uhci_submit_common() "breadth first" policy.  Drivers
-        * can submit urbs of any length, but longer ones might need many
-        * intervals to complete.
+       /* USB 1.1 interrupt transfers only involve one packet per interval.
+        * Drivers can submit URBs of any length, but longer ones will need
+        * multiple intervals to complete.
         */
-       return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
+       qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)];
+       return uhci_submit_common(uhci, urb, qh);
 }
 
 /*
  * Isochronous transfers
  */
-static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
-{
-       struct urb *last_urb = NULL;
-       struct urb_priv *up;
-       int ret = 0;
-
-       list_for_each_entry(up, &uhci->urb_list, urb_list) {
-               struct urb *u = up->urb;
-
-               /* look for pending URBs with identical pipe handle */
-               if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
-                   (u->status == -EINPROGRESS) && (u != urb)) {
-                       if (!last_urb)
-                               *start = u->start_frame;
-                       last_urb = u;
-               }
-       }
-
-       if (last_urb) {
-               *end = (last_urb->start_frame + last_urb->number_of_packets *
-                               last_urb->interval) & (UHCI_NUMFRAMES-1);
-               ret = 0;
-       } else
-               ret = -1;       /* no previous urb found */
-
-       return ret;
-}
-
-static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
+static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
+               struct uhci_qh *qh)
 {
-       int limits;
-       unsigned int start = 0, end = 0;
+       struct uhci_td *td = NULL;      /* Since urb->number_of_packets > 0 */
+       int i, frame;
+       unsigned long destination, status;
+       struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
        if (urb->number_of_packets > 900)       /* 900? Why? */
                return -EFBIG;
 
-       limits = isochronous_find_limits(uhci, urb, &start, &end);
+       status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+       destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
+       /* Figure out the starting frame number */
        if (urb->transfer_flags & URB_ISO_ASAP) {
-               if (limits) {
+               if (list_empty(&qh->queue)) {
                        uhci_get_current_frame_number(uhci);
-                       urb->start_frame = (uhci->frame_number + 10)
-                                       & (UHCI_NUMFRAMES - 1);
-               } else
-                       urb->start_frame = end;
+                       urb->start_frame = (uhci->frame_number + 10);
+
+               } else {                /* Go right after the last one */
+                       struct urb *last_urb;
+
+                       last_urb = list_entry(qh->queue.prev,
+                                       struct urb_priv, node)->urb;
+                       urb->start_frame = (last_urb->start_frame +
+                                       last_urb->number_of_packets *
+                                       last_urb->interval);
+               }
        } else {
-               urb->start_frame &= (UHCI_NUMFRAMES - 1);
                /* FIXME: Sanity check */
        }
-
-       return 0;
-}
-
-/*
- * Isochronous transfers
- */
-static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct uhci_td *td;
-       int i, ret, frame;
-       int status, destination;
-       struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
-
-       status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-       destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-       ret = isochronous_find_start(uhci, urb);
-       if (ret)
-               return ret;
+       urb->start_frame &= (UHCI_NUMFRAMES - 1);
 
        for (i = 0; i < urb->number_of_packets; i++) {
                td = uhci_alloc_td(uhci);
@@ -1092,20 +1012,25 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
                        return -ENOMEM;
 
                uhci_add_td_to_urb(urb, td);
-               uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length),
-                       urb->transfer_dma + urb->iso_frame_desc[i].offset);
-
-               if (i + 1 >= urb->number_of_packets)
-                       td->status |= cpu_to_le32(TD_CTRL_IOC);
+               uhci_fill_td(td, status, destination |
+                               uhci_explen(urb->iso_frame_desc[i].length),
+                               urb->transfer_dma +
+                                       urb->iso_frame_desc[i].offset);
        }
 
+       /* Set the interrupt-on-completion flag on the last packet. */
+       td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
+
+       qh->skel = uhci->skel_iso_qh;
+
+       /* Add the TDs to the frame list */
        frame = urb->start_frame;
        list_for_each_entry(td, &urbp->td_list, list) {
-               uhci_insert_td_frame_list(uhci, td, frame);
+               uhci_insert_td_in_frame_list(uhci, td, frame);
                frame += urb->interval;
        }
 
-       return -EINPROGRESS;
+       return 0;
 }
 
 static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
@@ -1139,80 +1064,67 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
 
                i++;
        }
-       unlink_isochronous_tds(uhci, urb);
 
        return ret;
 }
 
-static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct urb_priv *up;
-
-       /* We don't match Isoc transfers since they are special */
-       if (usb_pipeisoc(urb->pipe))
-               return NULL;
-
-       list_for_each_entry(up, &uhci->urb_list, urb_list) {
-               struct urb *u = up->urb;
-
-               if (u->dev == urb->dev && u->status == -EINPROGRESS) {
-                       /* For control, ignore the direction */
-                       if (usb_pipecontrol(urb->pipe) &&
-                           (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
-                               return u;
-                       else if (u->pipe == urb->pipe)
-                               return u;
-               }
-       }
-
-       return NULL;
-}
-
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
-               struct usb_host_endpoint *ep,
+               struct usb_host_endpoint *hep,
                struct urb *urb, gfp_t mem_flags)
 {
        int ret;
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned long flags;
-       struct urb *eurb;
+       struct urb_priv *urbp;
+       struct uhci_qh *qh;
        int bustime;
 
        spin_lock_irqsave(&uhci->lock, flags);
 
        ret = urb->status;
        if (ret != -EINPROGRESS)                /* URB already unlinked! */
-               goto out;
+               goto done;
 
-       eurb = uhci_find_urb_ep(uhci, urb);
+       ret = -ENOMEM;
+       urbp = uhci_alloc_urb_priv(uhci, urb);
+       if (!urbp)
+               goto done;
 
-       if (!uhci_alloc_urb_priv(uhci, urb)) {
-               ret = -ENOMEM;
-               goto out;
+       if (hep->hcpriv)
+               qh = (struct uhci_qh *) hep->hcpriv;
+       else {
+               qh = uhci_alloc_qh(uhci, urb->dev, hep);
+               if (!qh)
+                       goto err_no_qh;
        }
+       urbp->qh = qh;
 
        switch (usb_pipetype(urb->pipe)) {
        case PIPE_CONTROL:
-               ret = uhci_submit_control(uhci, urb, eurb);
+               ret = uhci_submit_control(uhci, urb, qh);
+               break;
+       case PIPE_BULK:
+               ret = uhci_submit_bulk(uhci, urb, qh);
                break;
        case PIPE_INTERRUPT:
-               if (!eurb) {
+               if (list_empty(&qh->queue)) {
                        bustime = usb_check_bandwidth(urb->dev, urb);
                        if (bustime < 0)
                                ret = bustime;
                        else {
-                               ret = uhci_submit_interrupt(uhci, urb, eurb);
-                               if (ret == -EINPROGRESS)
+                               ret = uhci_submit_interrupt(uhci, urb, qh);
+                               if (ret == 0)
                                        usb_claim_bandwidth(urb->dev, urb, bustime, 0);
                        }
                } else {        /* inherit from parent */
-                       urb->bandwidth = eurb->bandwidth;
-                       ret = uhci_submit_interrupt(uhci, urb, eurb);
+                       struct urb_priv *eurbp;
+
+                       eurbp = list_entry(qh->queue.prev, struct urb_priv,
+                                       node);
+                       urb->bandwidth = eurbp->urb->bandwidth;
+                       ret = uhci_submit_interrupt(uhci, urb, qh);
                }
                break;
-       case PIPE_BULK:
-               ret = uhci_submit_bulk(uhci, urb, eurb);
-               break;
        case PIPE_ISOCHRONOUS:
                bustime = usb_check_bandwidth(urb->dev, urb);
                if (bustime < 0) {
@@ -1220,221 +1132,208 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
                        break;
                }
 
-               ret = uhci_submit_isochronous(uhci, urb);
-               if (ret == -EINPROGRESS)
+               ret = uhci_submit_isochronous(uhci, urb, qh);
+               if (ret == 0)
                        usb_claim_bandwidth(urb->dev, urb, bustime, 1);
                break;
        }
+       if (ret != 0)
+               goto err_submit_failed;
+
+       /* Add this URB to the QH */
+       urbp->qh = qh;
+       list_add_tail(&urbp->node, &qh->queue);
 
-       if (ret != -EINPROGRESS) {
-               /* Submit failed, so delete it from the urb_list */
-               struct urb_priv *urbp = urb->hcpriv;
+       /* If the new URB is the first and only one on this QH then either
+        * the QH is new and idle or else it's unlinked and waiting to
+        * become idle, so we can activate it right away. */
+       if (qh->queue.next == &urbp->node)
+               uhci_activate_qh(uhci, qh);
+       goto done;
 
-               list_del_init(&urbp->urb_list);
-               uhci_destroy_urb_priv(uhci, urb);
-       } else
-               ret = 0;
+err_submit_failed:
+       if (qh->state == QH_STATE_IDLE)
+               uhci_make_qh_idle(uhci, qh);    /* Reclaim unused QH */
 
-out:
+err_no_qh:
+       uhci_free_urb_priv(uhci, urbp);
+
+done:
        spin_unlock_irqrestore(&uhci->lock, flags);
        return ret;
 }
 
-/*
- * Return the result of a transfer
- */
-static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 {
-       int ret = -EINPROGRESS;
+       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       unsigned long flags;
        struct urb_priv *urbp;
 
-       spin_lock(&urb->lock);
+       spin_lock_irqsave(&uhci->lock, flags);
+       urbp = urb->hcpriv;
+       if (!urbp)                      /* URB was never linked! */
+               goto done;
+
+       /* Remove Isochronous TDs from the frame list ASAP */
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+               uhci_unlink_isochronous_tds(uhci, urb);
+       uhci_unlink_qh(uhci, urbp->qh);
+
+done:
+       spin_unlock_irqrestore(&uhci->lock, flags);
+       return 0;
+}
 
-       urbp = (struct urb_priv *)urb->hcpriv;
+/*
+ * Finish unlinking an URB and give it back
+ */
+static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
+               struct urb *urb, struct pt_regs *regs)
+__releases(uhci->lock)
+__acquires(uhci->lock)
+{
+       struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
-       if (urb->status != -EINPROGRESS)        /* URB already dequeued */
-               goto out;
+       /* Isochronous TDs get unlinked directly from the frame list */
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+               uhci_unlink_isochronous_tds(uhci, urb);
+
+       /* If the URB isn't first on its queue, adjust the link pointer
+        * of the last TD in the previous URB. */
+       else if (qh->queue.next != &urbp->node) {
+               struct urb_priv *purbp;
+               struct uhci_td *ptd, *ltd;
+
+               purbp = list_entry(urbp->node.prev, struct urb_priv, node);
+               ptd = list_entry(purbp->td_list.prev, struct uhci_td,
+                               list);
+               ltd = list_entry(urbp->td_list.prev, struct uhci_td,
+                               list);
+               ptd->link = ltd->link;
+       }
 
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
-               ret = uhci_result_control(uhci, urb);
-               break;
-       case PIPE_BULK:
-       case PIPE_INTERRUPT:
-               ret = uhci_result_common(uhci, urb);
-               break;
-       case PIPE_ISOCHRONOUS:
-               ret = uhci_result_isochronous(uhci, urb);
-               break;
+       /* Take the URB off the QH's queue.  If the queue is now empty,
+        * this is a perfect time for a toggle fixup. */
+       list_del_init(&urbp->node);
+       if (list_empty(&qh->queue) && qh->needs_fixup) {
+               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                               usb_pipeout(urb->pipe), qh->initial_toggle);
+               qh->needs_fixup = 0;
        }
 
-       if (ret == -EINPROGRESS)
-               goto out;
-       urb->status = ret;
+       uhci_dec_fsbr(uhci, urb);       /* Safe since it checks */
+       uhci_free_urb_priv(uhci, urbp);
 
        switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
-       case PIPE_BULK:
        case PIPE_ISOCHRONOUS:
                /* Release bandwidth for Interrupt or Isoc. transfers */
                if (urb->bandwidth)
                        usb_release_bandwidth(urb->dev, urb, 1);
-               uhci_unlink_generic(uhci, urb);
                break;
        case PIPE_INTERRUPT:
                /* Release bandwidth for Interrupt or Isoc. transfers */
                /* Make sure we don't release if we have a queued URB */
-               if (list_empty(&urbp->queue_list) && urb->bandwidth)
+               if (list_empty(&qh->queue) && urb->bandwidth)
                        usb_release_bandwidth(urb->dev, urb, 0);
                else
                        /* bandwidth was passed on to queued URB, */
                        /* so don't let usb_unlink_urb() release it */
                        urb->bandwidth = 0;
-               uhci_unlink_generic(uhci, urb);
                break;
-       default:
-               dev_info(uhci_dev(uhci), "%s: unknown pipe type %d "
-                               "for urb %p\n",
-                               __FUNCTION__, usb_pipetype(urb->pipe), urb);
        }
 
-       /* Move it from uhci->urb_list to uhci->complete_list */
-       uhci_moveto_complete(uhci, urbp);
-
-out:
-       spin_unlock(&urb->lock);
-}
-
-static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct list_head *head;
-       struct uhci_td *td;
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       int prevactive = 0;
-
-       uhci_dec_fsbr(uhci, urb);       /* Safe since it checks */
+       spin_unlock(&uhci->lock);
+       usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, regs);
+       spin_lock(&uhci->lock);
 
-       /*
-        * Now we need to find out what the last successful toggle was
-        * so we can update the local data toggle for the next transfer
-        *
-        * There are 2 ways the last successful completed TD is found:
-        *
-        * 1) The TD is NOT active and the actual length < expected length
-        * 2) The TD is NOT active and it's the last TD in the chain
-        *
-        * and a third way the first uncompleted TD is found:
-        *
-        * 3) The TD is active and the previous TD is NOT active
-        *
-        * Control and Isochronous ignore the toggle, so this is safe
-        * for all types
-        *
-        * FIXME: The toggle fixups won't be 100% reliable until we
-        * change over to using a single queue for each endpoint and
-        * stop the queue before unlinking.
-        */
-       head = &urbp->td_list;
-       list_for_each_entry(td, head, list) {
-               unsigned int ctrlstat = td_status(td);
+       /* If the queue is now empty, we can unlink the QH and give up its
+        * reserved bandwidth. */
+       if (list_empty(&qh->queue)) {
+               uhci_unlink_qh(uhci, qh);
 
-               if (!(ctrlstat & TD_CTRL_ACTIVE) &&
-                               (uhci_actual_length(ctrlstat) <
-                                uhci_expected_length(td_token(td)) ||
-                               td->list.next == head))
-                       usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
-                               uhci_packetout(td_token(td)),
-                               uhci_toggle(td_token(td)) ^ 1);
-               else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive)
-                       usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
-                               uhci_packetout(td_token(td)),
-                               uhci_toggle(td_token(td)));
-
-               prevactive = ctrlstat & TD_CTRL_ACTIVE;
+               /* Bandwidth stuff not yet implemented */
        }
-
-       uhci_delete_queued_urb(uhci, urb);
-
-       /* The interrupt loop will reclaim the QHs */
-       uhci_remove_qh(uhci, urbp->qh);
-       urbp->qh = NULL;
 }
 
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+/*
+ * Scan the URBs in a QH's queue
+ */
+#define QH_FINISHED_UNLINKING(qh)                      \
+               (qh->state == QH_STATE_UNLINKING &&     \
+               uhci->frame_number + uhci->is_stopped != qh->unlink_frame)
+
+static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
+               struct pt_regs *regs)
 {
-       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       unsigned long flags;
        struct urb_priv *urbp;
+       struct urb *urb;
+       int status;
 
-       spin_lock_irqsave(&uhci->lock, flags);
-       urbp = urb->hcpriv;
-       if (!urbp)                      /* URB was never linked! */
-               goto done;
-       list_del_init(&urbp->urb_list);
-
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
-               unlink_isochronous_tds(uhci, urb);
-       uhci_unlink_generic(uhci, urb);
-
-       uhci_get_current_frame_number(uhci);
-       if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) {
-               uhci_remove_pending_urbps(uhci);
-               uhci->urb_remove_age = uhci->frame_number;
-       }
-
-       /* If we're the first, set the next interrupt bit */
-       if (list_empty(&uhci->urb_remove_list))
-               uhci_set_next_interrupt(uhci);
-       list_add_tail(&urbp->urb_list, &uhci->urb_remove_list);
-
-done:
-       spin_unlock_irqrestore(&uhci->lock, flags);
-       return 0;
-}
+       while (!list_empty(&qh->queue)) {
+               urbp = list_entry(qh->queue.next, struct urb_priv, node);
+               urb = urbp->urb;
 
-static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       struct list_head *head;
-       struct uhci_td *td;
-       int count = 0;
-
-       uhci_dec_fsbr(uhci, urb);
+               switch (usb_pipetype(urb->pipe)) {
+               case PIPE_CONTROL:
+                       status = uhci_result_control(uhci, urb);
+                       break;
+               case PIPE_ISOCHRONOUS:
+                       status = uhci_result_isochronous(uhci, urb);
+                       break;
+               default:        /* PIPE_BULK or PIPE_INTERRUPT */
+                       status = uhci_result_common(uhci, urb);
+                       break;
+               }
+               if (status == -EINPROGRESS)
+                       break;
 
-       urbp->fsbr_timeout = 1;
+               spin_lock(&urb->lock);
+               if (urb->status == -EINPROGRESS)        /* Not dequeued */
+                       urb->status = status;
+               else
+                       status = -ECONNRESET;
+               spin_unlock(&urb->lock);
 
-       /*
-        * Ideally we would want to fix qh->element as well, but it's
-        * read/write by the HC, so that can introduce a race. It's not
-        * really worth the hassle
-        */
+               /* Dequeued but completed URBs can't be given back unless
+                * the QH is stopped or has finished unlinking. */
+               if (status == -ECONNRESET &&
+                               !(qh->is_stopped || QH_FINISHED_UNLINKING(qh)))
+                       return;
 
-       head = &urbp->td_list;
-       list_for_each_entry(td, head, list) {
-               /*
-                * Make sure we don't do the last one (since it'll have the
-                * TERM bit set) as well as we skip every so many TDs to
-                * make sure it doesn't hog the bandwidth
-                */
-               if (td->list.next != head && (count % DEPTH_INTERVAL) ==
-                               (DEPTH_INTERVAL - 1))
-                       td->link |= UHCI_PTR_DEPTH;
-
-               count++;
+               uhci_giveback_urb(uhci, qh, urb, regs);
+               if (qh->is_stopped)
+                       break;
        }
 
-       return 0;
-}
-
-static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
-{
-       struct uhci_qh *qh, *tmp;
-
-       list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) {
-               list_del_init(&qh->remove_list);
+       /* If the QH is neither stopped nor finished unlinking (normal case),
+        * our work here is done. */
+ restart:
+       if (!(qh->is_stopped || QH_FINISHED_UNLINKING(qh)))
+               return;
 
-               uhci_free_qh(uhci, qh);
+       /* Otherwise give back each of the dequeued URBs */
+       list_for_each_entry(urbp, &qh->queue, node) {
+               urb = urbp->urb;
+               if (urb->status != -EINPROGRESS) {
+                       uhci_save_toggle(qh, urb);
+                       uhci_giveback_urb(uhci, qh, urb, regs);
+                       goto restart;
+               }
+       }
+       qh->is_stopped = 0;
+
+       /* There are no more dequeued URBs.  If there are still URBs on the
+        * queue, the QH can now be re-activated. */
+       if (!list_empty(&qh->queue)) {
+               if (qh->needs_fixup)
+                       uhci_fixup_toggles(qh, 0);
+               uhci_activate_qh(uhci, qh);
        }
+
+       /* The queue is empty.  The QH can become idle if it is fully
+        * unlinked. */
+       else if (QH_FINISHED_UNLINKING(qh))
+               uhci_make_qh_idle(uhci, qh);
 }
 
 static void uhci_free_pending_tds(struct uhci_hcd *uhci)
@@ -1448,43 +1347,13 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci)
        }
 }
 
-static void
-uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
-__releases(uhci->lock)
-__acquires(uhci->lock)
-{
-       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
-       uhci_destroy_urb_priv(uhci, urb);
-
-       spin_unlock(&uhci->lock);
-       usb_hcd_giveback_urb(hcd, urb, regs);
-       spin_lock(&uhci->lock);
-}
-
-static void uhci_finish_completion(struct uhci_hcd *uhci, struct pt_regs *regs)
-{
-       struct urb_priv *urbp, *tmp;
-
-       list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) {
-               struct urb *urb = urbp->urb;
-
-               list_del_init(&urbp->urb_list);
-               uhci_finish_urb(uhci_to_hcd(uhci), urb, regs);
-       }
-}
-
-static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
-{
-
-       /* Splice the urb_remove_list onto the end of the complete_list */
-       list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
-}
-
-/* Process events in the schedule, but only in one thread at a time */
+/*
+ * Process events in the schedule, but only in one thread at a time
+ */
 static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
 {
-       struct urb_priv *urbp, *tmp;
+       int i;
+       struct uhci_qh *qh;
 
        /* Don't allow re-entrant calls */
        if (uhci->scan_in_progress) {
@@ -1498,60 +1367,39 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
        uhci_clear_next_interrupt(uhci);
        uhci_get_current_frame_number(uhci);
 
-       if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
-               uhci_free_pending_qhs(uhci);
        if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
                uhci_free_pending_tds(uhci);
-       if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age)
-               uhci_remove_pending_urbps(uhci);
-
-       /* Walk the list of pending URBs to see which ones completed
-        * (must be _safe because uhci_transfer_result() dequeues URBs) */
-       list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) {
-               struct urb *urb = urbp->urb;
 
-               /* Checks the status and does all of the magic necessary */
-               uhci_transfer_result(uhci, urb);
-       }
-       uhci_finish_completion(uhci, regs);
-
-       /* If the controller is stopped, we can finish these off right now */
-       if (uhci->is_stopped) {
-               uhci_free_pending_qhs(uhci);
-               uhci_free_pending_tds(uhci);
-               uhci_remove_pending_urbps(uhci);
+       /* Go through all the QH queues and process the URBs in each one */
+       for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
+               uhci->next_qh = list_entry(uhci->skelqh[i]->node.next,
+                               struct uhci_qh, node);
+               while ((qh = uhci->next_qh) != uhci->skelqh[i]) {
+                       uhci->next_qh = list_entry(qh->node.next,
+                                       struct uhci_qh, node);
+                       uhci_scan_qh(uhci, qh, regs);
+               }
        }
 
        if (uhci->need_rescan)
                goto rescan;
        uhci->scan_in_progress = 0;
 
-       if (list_empty(&uhci->urb_remove_list) &&
-           list_empty(&uhci->td_remove_list) &&
-           list_empty(&uhci->qh_remove_list))
+       /* If the controller is stopped, we can finish these off right now */
+       if (uhci->is_stopped)
+               uhci_free_pending_tds(uhci);
+
+       if (list_empty(&uhci->td_remove_list) &&
+                       list_empty(&uhci->skel_unlink_qh->node))
                uhci_clear_next_interrupt(uhci);
        else
                uhci_set_next_interrupt(uhci);
-
-       /* Wake up anyone waiting for an URB to complete */
-       wake_up_all(&uhci->waitqh);
 }
 
 static void check_fsbr(struct uhci_hcd *uhci)
 {
-       struct urb_priv *up;
-
-       list_for_each_entry(up, &uhci->urb_list, urb_list) {
-               struct urb *u = up->urb;
-
-               spin_lock(&u->lock);
-
-               /* Check if the FSBR timed out */
-               if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
-                       uhci_fsbr_timeout(uhci, u);
-
-               spin_unlock(&u->lock);
-       }
+       /* For now, don't scan URBs for FSBR timeouts.
+        * Add it back in later... */
 
        /* Really disable FSBR */
        if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
index 0498711..08daf40 100644 (file)
@@ -96,6 +96,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 
 #include <linux/usb.h>
 #include <linux/fs.h>
@@ -169,7 +170,7 @@ struct mdc800_data
        int                     out_count;      // Bytes in the buffer
 
        int                     open;           // Camera device open ?
-       struct semaphore        io_lock;        // IO -lock
+       struct mutex            io_lock;        // IO -lock
 
        char                    in [8];         // Command Input Buffer
        int                     in_count;
@@ -497,7 +498,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
 
        info ("Found Mustek MDC800 on USB.");
 
-       down (&mdc800->io_lock);
+       mutex_lock(&mdc800->io_lock);
 
        retval = usb_register_dev(intf, &mdc800_class);
        if (retval) {
@@ -542,7 +543,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
 
        mdc800->state=READY;
 
-       up (&mdc800->io_lock);
+       mutex_unlock(&mdc800->io_lock);
        
        usb_set_intfdata(intf, mdc800);
        return 0;
@@ -620,7 +621,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
        int retval=0;
        int errn=0;
 
-       down (&mdc800->io_lock);
+       mutex_lock(&mdc800->io_lock);
        
        if (mdc800->state == NOT_CONNECTED)
        {
@@ -656,7 +657,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
        dbg ("Mustek MDC800 device opened.");
 
 error_out:
-       up (&mdc800->io_lock);
+       mutex_unlock(&mdc800->io_lock);
        return errn;
 }
 
@@ -669,7 +670,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
        int retval=0;
        dbg ("Mustek MDC800 device closed.");
 
-       down (&mdc800->io_lock);
+       mutex_lock(&mdc800->io_lock);
        if (mdc800->open && (mdc800->state != NOT_CONNECTED))
        {
                usb_kill_urb(mdc800->irq_urb);
@@ -682,7 +683,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
                retval=-EIO;
        }
 
-       up(&mdc800->io_lock);
+       mutex_unlock(&mdc800->io_lock);
        return retval;
 }
 
@@ -695,21 +696,21 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
        size_t left=len, sts=len; /* single transfer size */
        char __user *ptr = buf;
 
-       down (&mdc800->io_lock);
+       mutex_lock(&mdc800->io_lock);
        if (mdc800->state == NOT_CONNECTED)
        {
-               up (&mdc800->io_lock);
+               mutex_unlock(&mdc800->io_lock);
                return -EBUSY;
        }
        if (mdc800->state == WORKING)
        {
                warn ("Illegal State \"working\" reached during read ?!");
-               up (&mdc800->io_lock);
+               mutex_unlock(&mdc800->io_lock);
                return -EBUSY;
        }
        if (!mdc800->open)
        {
-               up (&mdc800->io_lock);
+               mutex_unlock(&mdc800->io_lock);
                return -EBUSY;
        }
 
@@ -717,7 +718,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
        {
                if (signal_pending (current)) 
                {
-                       up (&mdc800->io_lock);
+                       mutex_unlock(&mdc800->io_lock);
                        return -EINTR;
                }
 
@@ -736,7 +737,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
                                if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
                                {
                                        err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
-                                       up (&mdc800->io_lock);
+                                       mutex_unlock(&mdc800->io_lock);
                                        return len-left;
                                }
                                wait_event_timeout(mdc800->download_wait, mdc800->downloaded,
@@ -745,14 +746,14 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
                                if (mdc800->download_urb->status != 0)
                                {
                                        err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
-                                       up (&mdc800->io_lock);
+                                       mutex_unlock(&mdc800->io_lock);
                                        return len-left;
                                }
                        }
                        else
                        {
                                /* No more bytes -> that's an error*/
-                               up (&mdc800->io_lock);
+                               mutex_unlock(&mdc800->io_lock);
                                return -EIO;
                        }
                }
@@ -761,7 +762,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
                        /* Copy Bytes */
                        if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr],
                                                sts)) {
-                               up(&mdc800->io_lock);
+                               mutex_unlock(&mdc800->io_lock);
                                return -EFAULT;
                        }
                        ptr+=sts;
@@ -770,7 +771,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
                }
        }
 
-       up (&mdc800->io_lock);
+       mutex_unlock(&mdc800->io_lock);
        return len-left;
 }
 
@@ -785,15 +786,15 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 {
        size_t i=0;
 
-       down (&mdc800->io_lock);
+       mutex_lock(&mdc800->io_lock);
        if (mdc800->state != READY)
        {
-               up (&mdc800->io_lock);
+               mutex_unlock(&mdc800->io_lock);
                return -EBUSY;
        }
        if (!mdc800->open )
        {
-               up (&mdc800->io_lock);
+               mutex_unlock(&mdc800->io_lock);
                return -EBUSY;
        }
 
@@ -802,13 +803,13 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                unsigned char c;
                if (signal_pending (current)) 
                {
-                       up (&mdc800->io_lock);
+                       mutex_unlock(&mdc800->io_lock);
                        return -EINTR;
                }
                
                if(get_user(c, buf+i))
                {
-                       up(&mdc800->io_lock);
+                       mutex_unlock(&mdc800->io_lock);
                        return -EFAULT;
                }
 
@@ -829,7 +830,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                }
                else
                {
-                       up (&mdc800->io_lock);
+                       mutex_unlock(&mdc800->io_lock);
                        return -EIO;
                }
 
@@ -841,7 +842,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                        if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
                        {
                                err ("Camera didn't get ready.\n");
-                               up (&mdc800->io_lock);
+                               mutex_unlock(&mdc800->io_lock);
                                return -EIO;
                        }
 
@@ -853,7 +854,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                        if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
                        {
                                err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
-                               up (&mdc800->io_lock);
+                               mutex_unlock(&mdc800->io_lock);
                                return -EIO;
                        }
                        wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000);
@@ -861,7 +862,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                        if (mdc800->state == WORKING)
                        {
                                usb_kill_urb(mdc800->write_urb);
-                               up (&mdc800->io_lock);
+                               mutex_unlock(&mdc800->io_lock);
                                return -EIO;
                        }
 
@@ -873,7 +874,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                                        {
                                                err ("call 0x07 before 0x05,0x3e");
                                                mdc800->state=READY;
-                                               up (&mdc800->io_lock);
+                                               mutex_unlock(&mdc800->io_lock);
                                                return -EIO;
                                        }
                                        mdc800->pic_len=-1;
@@ -892,7 +893,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                                                if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
                                                {
                                                        err ("requesting answer from irq fails");
-                                                       up (&mdc800->io_lock);
+                                                       mutex_unlock(&mdc800->io_lock);
                                                        return -EIO;
                                                }
 
@@ -920,7 +921,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                                                if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
                                                {
                                                        err ("Command Timeout.");
-                                                       up (&mdc800->io_lock);
+                                                       mutex_unlock(&mdc800->io_lock);
                                                        return -EIO;
                                                }
                                        }
@@ -930,7 +931,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                }
                i++;
        }
-       up (&mdc800->io_lock);
+       mutex_unlock(&mdc800->io_lock);
        return i;
 }
 
@@ -978,15 +979,13 @@ static int __init usb_mdc800_init (void)
 {
        int retval = -ENODEV;
        /* Allocate Memory */
-       mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL);
+       mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL);
        if (!mdc800)
                goto cleanup_on_fail;
 
-       memset(mdc800, 0, sizeof(struct mdc800_data));
        mdc800->dev = NULL;
-       mdc800->open=0;
        mdc800->state=NOT_CONNECTED;
-       init_MUTEX (&mdc800->io_lock);
+       mutex_init (&mdc800->io_lock);
 
        init_waitqueue_head (&mdc800->irq_wait);
        init_waitqueue_head (&mdc800->write_wait);
index f7bdc50..99f986c 100644 (file)
@@ -159,8 +159,6 @@ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
  */
 #define FILTER_TIME (HZ / 20)
 
-static DECLARE_MUTEX(disconnect_sem);
-
 struct ati_remote {
        struct input_dev *idev;
        struct usb_device *udev;
index 07a012f..58b59f6 100644 (file)
@@ -66,9 +66,8 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne
        if (report_enum->report_id_hash[id])
                return report_enum->report_id_hash[id];
 
-       if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
+       if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
                return NULL;
-       memset(report, 0, sizeof(struct hid_report));
 
        if (id != 0)
                report_enum->numbered = 1;
@@ -97,12 +96,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
                return NULL;
        }
 
-       if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+       if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
                + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
 
-       memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-               + values * sizeof(unsigned));
-
        field->index = report->maxfield++;
        report->field[field->index] = field;
        field->usage = (struct hid_usage *)(field + 1);
@@ -651,17 +647,14 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
                hid_parser_reserved
        };
 
-       if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
+       if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
                return NULL;
-       memset(device, 0, sizeof(struct hid_device));
 
-       if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
+       if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
                                   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
                kfree(device);
                return NULL;
        }
-       memset(device->collection, 0, sizeof(struct hid_collection) *
-               HID_DEFAULT_NUM_COLLECTIONS);
        device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 
        for (i = 0; i < HID_REPORT_TYPES; i++)
@@ -675,13 +668,12 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
        memcpy(device->rdesc, start, size);
        device->rsize = size;
 
-       if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+       if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
                kfree(device->rdesc);
                kfree(device->collection);
                kfree(device);
                return NULL;
        }
-       memset(parser, 0, sizeof(struct hid_parser));
        parser->device = device;
 
        end = start + size;
@@ -911,6 +903,99 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_
 }
 
 /*
+ * Input submission and I/O error handler.
+ */
+
+static void hid_io_error(struct hid_device *hid);
+
+/* Start up the input URB */
+static int hid_start_in(struct hid_device *hid)
+{
+       unsigned long flags;
+       int rc = 0;
+
+       spin_lock_irqsave(&hid->inlock, flags);
+       if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) &&
+                       !test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) {
+               rc = usb_submit_urb(hid->urbin, GFP_ATOMIC);
+               if (rc != 0)
+                       clear_bit(HID_IN_RUNNING, &hid->iofl);
+       }
+       spin_unlock_irqrestore(&hid->inlock, flags);
+       return rc;
+}
+
+/* I/O retry timer routine */
+static void hid_retry_timeout(unsigned long _hid)
+{
+       struct hid_device *hid = (struct hid_device *) _hid;
+
+       dev_dbg(&hid->intf->dev, "retrying intr urb\n");
+       if (hid_start_in(hid))
+               hid_io_error(hid);
+}
+
+/* Workqueue routine to reset the device */
+static void hid_reset(void *_hid)
+{
+       struct hid_device *hid = (struct hid_device *) _hid;
+       int rc_lock, rc;
+
+       dev_dbg(&hid->intf->dev, "resetting device\n");
+       rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
+       if (rc_lock >= 0) {
+               rc = usb_reset_device(hid->dev);
+               if (rc_lock)
+                       usb_unlock_device(hid->dev);
+       }
+       clear_bit(HID_RESET_PENDING, &hid->iofl);
+
+       if (rc == 0) {
+               hid->retry_delay = 0;
+               if (hid_start_in(hid))
+                       hid_io_error(hid);
+       } else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR))
+               err("can't reset device, %s-%s/input%d, status %d",
+                               hid->dev->bus->bus_name,
+                               hid->dev->devpath,
+                               hid->ifnum, rc);
+}
+
+/* Main I/O error handler */
+static void hid_io_error(struct hid_device *hid)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hid->inlock, flags);
+
+       /* Stop when disconnected */
+       if (usb_get_intfdata(hid->intf) == NULL)
+               goto done;
+
+       /* When an error occurs, retry at increasing intervals */
+       if (hid->retry_delay == 0) {
+               hid->retry_delay = 13;  /* Then 26, 52, 104, 104, ... */
+               hid->stop_retry = jiffies + msecs_to_jiffies(1000);
+       } else if (hid->retry_delay < 100)
+               hid->retry_delay *= 2;
+
+       if (time_after(jiffies, hid->stop_retry)) {
+
+               /* Retries failed, so do a port reset */
+               if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {
+                       if (schedule_work(&hid->reset_work))
+                               goto done;
+                       clear_bit(HID_RESET_PENDING, &hid->iofl);
+               }
+       }
+
+       mod_timer(&hid->io_retry,
+                       jiffies + msecs_to_jiffies(hid->retry_delay));
+done:
+       spin_unlock_irqrestore(&hid->inlock, flags);
+}
+
+/*
  * Input interrupt completion handler.
  */
 
@@ -921,25 +1006,35 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
 
        switch (urb->status) {
                case 0:                 /* success */
+                       hid->retry_delay = 0;
                        hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
                        break;
                case -ECONNRESET:       /* unlink */
                case -ENOENT:
-               case -EPERM:
                case -ESHUTDOWN:        /* unplug */
-               case -EILSEQ:           /* unplug timeout on uhci */
+                       clear_bit(HID_IN_RUNNING, &hid->iofl);
                        return;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
                case -ETIMEDOUT:        /* NAK */
-                       break;
+                       clear_bit(HID_IN_RUNNING, &hid->iofl);
+                       hid_io_error(hid);
+                       return;
                default:                /* error */
                        warn("input irq status %d received", urb->status);
        }
 
        status = usb_submit_urb(urb, SLAB_ATOMIC);
-       if (status)
-               err("can't resubmit intr, %s-%s/input%d, status %d",
-                               hid->dev->bus->bus_name, hid->dev->devpath,
-                               hid->ifnum, status);
+       if (status) {
+               clear_bit(HID_IN_RUNNING, &hid->iofl);
+               if (status != -EPERM) {
+                       err("can't resubmit intr, %s-%s/input%d, status %d",
+                                       hid->dev->bus->bus_name,
+                                       hid->dev->devpath,
+                                       hid->ifnum, status);
+                       hid_io_error(hid);
+               }
+       }
 }
 
 /*
@@ -1101,8 +1196,9 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
                case 0:                 /* success */
                        break;
                case -ESHUTDOWN:        /* unplug */
-               case -EILSEQ:           /* unplug timeout on uhci */
                        unplug = 1;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
                case -ECONNRESET:       /* unlink */
                case -ENOENT:
                        break;
@@ -1149,8 +1245,9 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
                                hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
                        break;
                case -ESHUTDOWN:        /* unplug */
-               case -EILSEQ:           /* unplug timectrl on uhci */
                        unplug = 1;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
                case -ECONNRESET:       /* unlink */
                case -ENOENT:
                case -EPIPE:            /* report not available */
@@ -1263,14 +1360,9 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 
 int hid_open(struct hid_device *hid)
 {
-       if (hid->open++)
-               return 0;
-
-       hid->urbin->dev = hid->dev;
-
-       if (usb_submit_urb(hid->urbin, GFP_KERNEL))
-               return -EIO;
-
+       ++hid->open;
+       if (hid_start_in(hid))
+               hid_io_error(hid);
        return 0;
 }
 
@@ -1460,6 +1552,9 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_HP               0x03f0
 #define USB_DEVICE_ID_HP_USBHUB_KB     0x020c
 
+#define USB_VENDOR_ID_CREATIVELABS     0x062a
+#define USB_DEVICE_ID_CREATIVELABS_SILVERCREST 0x0201
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -1576,6 +1671,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
+       { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -1795,6 +1891,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 
        init_waitqueue_head(&hid->wait);
 
+       INIT_WORK(&hid->reset_work, hid_reset, hid);
+       setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid);
+
+       spin_lock_init(&hid->inlock);
        spin_lock_init(&hid->outlock);
        spin_lock_init(&hid->ctrllock);
 
@@ -1863,11 +1963,16 @@ static void hid_disconnect(struct usb_interface *intf)
        if (!hid)
                return;
 
+       spin_lock_irq(&hid->inlock);    /* Sync with error handler */
        usb_set_intfdata(intf, NULL);
+       spin_unlock_irq(&hid->inlock);
        usb_kill_urb(hid->urbin);
        usb_kill_urb(hid->urbout);
        usb_kill_urb(hid->urbctrl);
 
+       del_timer_sync(&hid->io_retry);
+       flush_scheduled_work();
+
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_disconnect(hid);
        if (hid->claimed & HID_CLAIMED_HIDDEV)
@@ -1942,6 +2047,10 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct hid_device *hid = usb_get_intfdata (intf);
 
+       spin_lock_irq(&hid->inlock);    /* Sync with error handler */
+       set_bit(HID_SUSPENDED, &hid->iofl);
+       spin_unlock_irq(&hid->inlock);
+       del_timer(&hid->io_retry);
        usb_kill_urb(hid->urbin);
        dev_dbg(&intf->dev, "suspend\n");
        return 0;
@@ -1952,10 +2061,8 @@ static int hid_resume(struct usb_interface *intf)
        struct hid_device *hid = usb_get_intfdata (intf);
        int status;
 
-       if (hid->open)
-               status = usb_submit_urb(hid->urbin, GFP_NOIO);
-       else
-               status = 0;
+       clear_bit(HID_SUSPENDED, &hid->iofl);
+       status = hid_start_in(hid);
        dev_dbg(&intf->dev, "resume status %d\n", status);
        return status;
 }
index f82c9c9..f07d443 100644 (file)
@@ -154,10 +154,9 @@ int hid_lgff_init(struct hid_device* hid)
                return -1;
        }
 
-       private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
+       private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL);
        if (!private)
                return -1;
-       memset(private, 0, sizeof(struct lgff_device));
        hid->ff_private = private;
 
        /* Input init */
@@ -228,13 +227,12 @@ static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report)
        }
        *ret->field[0] = *report->field[0];
 
-       ret->field[0]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL);
+       ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL);
        if (!ret->field[0]->value) {
                kfree(ret->field[0]);
                kfree(ret);
                return NULL;
        }
-       memset(ret->field[0]->value, 0, sizeof(s32[8]));
 
        return ret;
 }
index 023fd5a..534425c 100644 (file)
@@ -113,11 +113,10 @@ int hid_tmff_init(struct hid_device *hid)
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
        struct input_dev *input_dev = hidinput->input;
 
-       private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
+       private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
        if (!private)
                return -ENOMEM;
 
-       memset(private, 0, sizeof(struct tmff_device));
        hid->ff_private = private;
 
        /* Find the report to use */
index 8b0d434..4e1b784 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
 
 /*
  * USB HID (Human Interface Device) interface class code
@@ -370,6 +372,9 @@ struct hid_control_fifo {
 
 #define HID_CTRL_RUNNING       1
 #define HID_OUT_RUNNING                2
+#define HID_IN_RUNNING         3
+#define HID_RESET_PENDING      4
+#define HID_SUSPENDED          5
 
 struct hid_input {
        struct list_head list;
@@ -393,12 +398,17 @@ struct hid_device {                                                       /* device report descriptor */
        int ifnum;                                                      /* USB interface number */
 
        unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+       struct timer_list io_retry;                                     /* Retry timer */
+       unsigned long stop_retry;                                       /* Time to give up, in jiffies */
+       unsigned int retry_delay;                                       /* Delay length in ms */
+       struct work_struct reset_work;                                  /* Task context for resets */
 
        unsigned int bufsize;                                           /* URB buffer size */
 
        struct urb *urbin;                                              /* Input URB */
        char *inbuf;                                                    /* Input buffer */
        dma_addr_t inbuf_dma;                                           /* Input buffer dma */
+       spinlock_t inlock;                                              /* Input fifo spinlock */
 
        struct urb *urbctrl;                                            /* Control URB */
        struct usb_ctrlrequest *cr;                                     /* Control request struct */
index 925f5ab..6dd6666 100644 (file)
@@ -257,9 +257,8 @@ static int hiddev_open(struct inode * inode, struct file * file) {
        if (i >= HIDDEV_MINORS || !hiddev_table[i])
                return -ENODEV;
 
-       if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+       if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
                return -ENOMEM;
-       memset(list, 0, sizeof(struct hiddev_list));
 
        list->hiddev = hiddev_table[i];
        list->next = hiddev_table[i]->list;
@@ -754,9 +753,8 @@ int hiddev_connect(struct hid_device *hid)
        if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
                return -1;
 
-       if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+       if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
                return -1;
-       memset(hiddev, 0, sizeof(struct hiddev));
 
        retval = usb_register_dev(hid->intf, &hiddev_class);
        if (retval) {
index 0d3d2cc..189d40f 100644 (file)
@@ -191,6 +191,21 @@ config USB_W9968CF
          To compile this driver as a module, choose M here: the
          module will be called w9968cf.
 
+config USB_ZC0301
+       tristate "USB ZC0301 Image Processor and Control Chip support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for cameras based on the ZC0301
+         Image Processor and Control Chip.
+
+         See <file:Documentation/usb/zc0301.txt> for more informations.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called zc0301.
+
 config USB_PWC
        tristate "USB Philips Cameras"
        depends on USB && VIDEO_DEV
index 3957aa1..50e89a3 100644 (file)
@@ -2,8 +2,12 @@
 # Makefile for USB Media drivers
 #
 
-sn9c102-objs   := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
+sn9c102-objs   := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
+                  sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
+                  sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
+                  sn9c102_tas5130d1b.o
 et61x251-objs  := et61x251_core.o et61x251_tas5130d1b.o
+zc0301-objs    := zc0301_core.o zc0301_pas202bcb.o
 
 obj-$(CONFIG_USB_DABUSB)       += dabusb.o
 obj-$(CONFIG_USB_DSBR)         += dsbr100.o
@@ -16,4 +20,5 @@ obj-$(CONFIG_USB_SN9C102)     += sn9c102.o
 obj-$(CONFIG_USB_STV680)       += stv680.o
 obj-$(CONFIG_USB_VICAM)                += vicam.o usbvideo.o
 obj-$(CONFIG_USB_W9968CF)      += w9968cf.o
+obj-$(CONFIG_USB_ZC0301)       += zc0301.o
 obj-$(CONFIG_USB_PWC)           += pwc/
index 18d8eaf..1774ab7 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/delay.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include "dabusb.h"
 #include "dabfirmware.h"
@@ -217,12 +218,11 @@ static int dabusb_alloc_buffers (pdabusb_t s)
                 pipesize, packets, transfer_buffer_length);
 
        while (buffers < (s->total_buffer_size << 10)) {
-               b = (pbuff_t) kmalloc (sizeof (buff_t), GFP_KERNEL);
+               b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
                if (!b) {
-                       err("kmalloc(sizeof(buff_t))==NULL");
+                       err("kzalloc(sizeof(buff_t))==NULL");
                        goto err;
                }
-               memset (b, 0, sizeof (buff_t));
                b->s = s;
                b->purb = usb_alloc_urb(packets, GFP_KERNEL);
                if (!b->purb) {
@@ -571,7 +571,7 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
                        s->readptr = 0;
                }
        }
-      err:                     //up(&s->mutex);
+      err:                     //mutex_unlock(&s->mutex);
        return ret;
 }
 
@@ -586,10 +586,10 @@ static int dabusb_open (struct inode *inode, struct file *file)
        s = &dabusb[devnum - DABUSB_MINOR];
 
        dbg("dabusb_open");
-       down (&s->mutex);
+       mutex_lock(&s->mutex);
 
        while (!s->usbdev || s->opened) {
-               up (&s->mutex);
+               mutex_unlock(&s->mutex);
 
                if (file->f_flags & O_NONBLOCK) {
                        return -EBUSY;
@@ -599,15 +599,15 @@ static int dabusb_open (struct inode *inode, struct file *file)
                if (signal_pending (current)) {
                        return -EAGAIN;
                }
-               down (&s->mutex);
+               mutex_lock(&s->mutex);
        }
        if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
-               up(&s->mutex);
+               mutex_unlock(&s->mutex);
                err("set_interface failed");
                return -EINVAL;
        }
        s->opened = 1;
-       up (&s->mutex);
+       mutex_unlock(&s->mutex);
 
        file->f_pos = 0;
        file->private_data = s;
@@ -621,10 +621,10 @@ static int dabusb_release (struct inode *inode, struct file *file)
 
        dbg("dabusb_release");
 
-       down (&s->mutex);
+       mutex_lock(&s->mutex);
        dabusb_stop (s);
        dabusb_free_buffers (s);
-       up (&s->mutex);
+       mutex_unlock(&s->mutex);
 
        if (!s->remove_pending) {
                if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
@@ -649,10 +649,10 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
        if (s->remove_pending)
                return -EIO;
 
-       down (&s->mutex);
+       mutex_lock(&s->mutex);
 
        if (!s->usbdev) {
-               up (&s->mutex);
+               mutex_unlock(&s->mutex);
                return -EIO;
        }
 
@@ -692,7 +692,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
                ret = -ENOIOCTLCMD;
                break;
        }
-       up (&s->mutex);
+       mutex_unlock(&s->mutex);
        return ret;
 }
 
@@ -738,7 +738,7 @@ static int dabusb_probe (struct usb_interface *intf,
 
        s = &dabusb[intf->minor];
 
-       down (&s->mutex);
+       mutex_lock(&s->mutex);
        s->remove_pending = 0;
        s->usbdev = usbdev;
        s->devnum = intf->minor;
@@ -761,7 +761,7 @@ static int dabusb_probe (struct usb_interface *intf,
        }
        dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
        usb_set_intfdata (intf, s);
-       up (&s->mutex);
+       mutex_unlock(&s->mutex);
 
        retval = usb_register_dev(intf, &dabusb_class);
        if (retval) {
@@ -772,7 +772,7 @@ static int dabusb_probe (struct usb_interface *intf,
        return 0;
 
       reject:
-       up (&s->mutex);
+       mutex_unlock(&s->mutex);
        s->usbdev = NULL;
        return -ENODEV;
 }
@@ -829,7 +829,7 @@ static int __init dabusb_init (void)
        for (u = 0; u < NRDABUSB; u++) {
                pdabusb_t s = &dabusb[u];
                memset (s, 0, sizeof (dabusb_t));
-               init_MUTEX (&s->mutex);
+               mutex_init (&s->mutex);
                s->usbdev = NULL;
                s->total_buffer_size = buffers;
                init_waitqueue_head (&s->wait);
index 10b666e..96b03e4 100644 (file)
@@ -18,7 +18,7 @@ typedef enum { _stopped=0, _started } driver_state_t;
 
 typedef struct
 {
-       struct semaphore mutex;
+       struct mutex mutex;
        struct usb_device *usbdev;
        wait_queue_head_t wait;
        wait_queue_head_t remove_ok;
index 652238f..eee8afc 100644 (file)
@@ -33,7 +33,9 @@
 #include <linux/types.h>
 #include <linux/param.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
 
 #include "et61x251_sensor.h"
 
@@ -51,6 +53,7 @@
 #define ET61X251_ALTERNATE_SETTING   13
 #define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
 #define ET61X251_CTRL_TIMEOUT        100
+#define ET61X251_FRAME_TIMEOUT       2
 
 /*****************************************************************************/
 
@@ -127,15 +130,16 @@ struct et61x251_sysfs_attr {
 
 struct et61x251_module_param {
        u8 force_munmap;
+       u16 frame_timeout;
 };
 
-static DECLARE_MUTEX(et61x251_sysfs_lock);
+static DEFINE_MUTEX(et61x251_sysfs_lock);
 static DECLARE_RWSEM(et61x251_disconnect);
 
 struct et61x251_device {
        struct video_device* v4ldev;
 
-       struct et61x251_sensor* sensor;
+       struct et61x251_sensor sensor;
 
        struct usb_device* usbdev;
        struct urb* urb[ET61X251_URBS];
@@ -157,19 +161,28 @@ struct et61x251_device {
        enum et61x251_dev_state state;
        u8 users;
 
-       struct semaphore dev_sem, fileop_sem;
+       struct mutex dev_mutex, fileop_mutex;
        spinlock_t queue_lock;
        wait_queue_head_t open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
 
+struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
+{
+       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+               return cam;
+
+       return NULL;
+}
+
+
 void
 et61x251_attach_sensor(struct et61x251_device* cam,
                        struct et61x251_sensor* sensor)
 {
-       cam->sensor = sensor;
-       cam->sensor->usbdev = cam->usbdev;
+       memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
 }
 
 /*****************************************************************************/
@@ -212,7 +225,8 @@ do {                                                                          \
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
index 2c0171a..7cc01b8 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
-#include <linux/stddef.h>
 #include <linux/compiler.h>
 #include <linux/ioctl.h>
 #include <linux/poll.h>
@@ -50,8 +48,8 @@
 #define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
 #define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.01"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 1)
+#define ET61X251_MODULE_VERSION "1:1.02"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)
 
 /*****************************************************************************/
 
@@ -90,6 +88,16 @@ MODULE_PARM_DESC(force_munmap,
                  "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                  "\n");
 
+static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+                                       ET61X251_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "
+                 __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
+                 "\n");
+
 #ifdef ET61X251_DEBUG
 static unsigned short debug = ET61X251_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
@@ -111,8 +119,8 @@ static u32
 et61x251_request_buffers(struct et61x251_device* cam, u32 count,
                          enum et61x251_io_method io)
 {
-       struct v4l2_pix_format* p = &(cam->sensor->pix_format);
-       struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
        const size_t imagesize = cam->module_param.force_munmap ||
                                 io == IO_READ ?
                                 (p->width * p->height * p->priv) / 8 :
@@ -268,8 +276,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam,
        int err = 0, res;
 
        data[0] = address;
-       data[1] = cam->sensor->i2c_slave_id;
-       data[2] = cam->sensor->rsta | 0x10;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x10;
        data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
                              0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
@@ -301,8 +309,8 @@ et61x251_i2c_try_write(struct et61x251_device* cam,
        int err = 0, res;
 
        data[0] = address;
-       data[1] = cam->sensor->i2c_slave_id;
-       data[2] = cam->sensor->rsta | 0x12;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x12;
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
                              0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
        if (res < 0)
@@ -334,9 +342,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
        u8* data = cam->control_buffer;
        int err = 0, res;
 
-       if (!cam->sensor)
-               return -1;
-
        data[0] = data2;
        data[1] = data3;
        data[2] = data4;
@@ -350,8 +355,8 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
                err += res;
 
        data[0] = address;
-       data[1] = cam->sensor->i2c_slave_id;
-       data[2] = cam->sensor->rsta | 0x02 | (n << 4);
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x02 | (n << 4);
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
                              0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
        if (res < 0)
@@ -364,11 +369,11 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
        if (res < 0)
                err += res;
 
-       err += et61x251_i2c_wait(cam, cam->sensor);
+       err += et61x251_i2c_wait(cam, &cam->sensor);
 
        if (err)
                DBG(3, "I2C raw write failed for %s image sensor",
-                   cam->sensor->name);
+                   cam->sensor.name);
 
        PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
              "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
@@ -382,19 +387,13 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
 
 int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
 {
-       if (!cam->sensor)
-               return -1;
-
-       return et61x251_i2c_try_read(cam, cam->sensor, address);
+       return et61x251_i2c_try_read(cam, &cam->sensor, address);
 }
 
 
 int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
 {
-       if (!cam->sensor)
-               return -1;
-
-       return et61x251_i2c_try_write(cam, cam->sensor, address, value);
+       return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
 }
 
 /*****************************************************************************/
@@ -417,7 +416,7 @@ static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
                if ((*f))
                        (*f)->state = F_QUEUED;
                DBG(3, "Stream interrupted");
-               wake_up_interruptible(&cam->wait_stream);
+               wake_up(&cam->wait_stream);
        }
 
        if (cam->state & DEV_DISCONNECTED)
@@ -435,9 +434,9 @@ static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
                (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
                                  frame);
 
-       imagesize = (cam->sensor->pix_format.width *
-                    cam->sensor->pix_format.height *
-                    cam->sensor->pix_format.priv) / 8;
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
 
        for (i = 0; i < urb->number_of_packets; i++) {
                unsigned int len, status;
@@ -476,7 +475,7 @@ start_of_frame:
 
                if ((*f)->state == F_GRABBING) {
                        if (sof && (*f)->buf.bytesused) {
-                               if (cam->sensor->pix_format.pixelformat ==
+                               if (cam->sensor.pix_format.pixelformat ==
                                                         V4L2_PIX_FMT_ET61X251)
                                        goto end_of_frame;
                                else {
@@ -521,7 +520,7 @@ end_of_frame:
                                        goto resubmit_urb;
 
                                if (sof &&
-                                   cam->sensor->pix_format.pixelformat ==
+                                   cam->sensor.pix_format.pixelformat ==
                                                         V4L2_PIX_FMT_ET61X251)
                                        goto start_of_frame;
                        }
@@ -650,21 +649,21 @@ static int et61x251_stop_transfer(struct et61x251_device* cam)
 
 static int et61x251_stream_interrupt(struct et61x251_device* cam)
 {
-       int err = 0;
+       long timeout;
 
        cam->stream = STREAM_INTERRUPT;
-       err = wait_event_timeout(cam->wait_stream,
-                                (cam->stream == STREAM_OFF) ||
-                                (cam->state & DEV_DISCONNECTED),
-                                ET61X251_URB_TIMEOUT);
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    ET61X251_URB_TIMEOUT);
        if (cam->state & DEV_DISCONNECTED)
                return -ENODEV;
-       else if (err) {
+       else if (cam->stream != STREAM_OFF) {
                cam->state |= DEV_MISCONFIGURED;
                DBG(1, "URB timeout reached. The camera is misconfigured. To "
                       "use it, close and open /dev/video%d again.",
                    cam->v4ldev->minor);
-               return err;
+               return -EIO;
        }
 
        return 0;
@@ -709,18 +708,18 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
        struct et61x251_device* cam;
        ssize_t count;
 
-       if (down_interruptible(&et61x251_sysfs_lock))
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENODEV;
        }
 
        count = sprintf(buf, "%u\n", cam->sysfs.reg);
 
-       up(&et61x251_sysfs_lock);
+       mutex_unlock(&et61x251_sysfs_lock);
 
        return count;
 }
@@ -733,18 +732,18 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
        u8 index;
        ssize_t count;
 
-       if (down_interruptible(&et61x251_sysfs_lock))
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENODEV;
        }
 
        index = et61x251_strtou8(buf, len, &count);
        if (index > 0x8e || !count) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -EINVAL;
        }
 
@@ -753,7 +752,7 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
        DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&et61x251_sysfs_lock);
+       mutex_unlock(&et61x251_sysfs_lock);
 
        return count;
 }
@@ -765,17 +764,17 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
        ssize_t count;
        int val;
 
-       if (down_interruptible(&et61x251_sysfs_lock))
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENODEV;
        }
 
        if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -EIO;
        }
 
@@ -783,7 +782,7 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&et61x251_sysfs_lock);
+       mutex_unlock(&et61x251_sysfs_lock);
 
        return count;
 }
@@ -797,24 +796,24 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
        ssize_t count;
        int err;
 
-       if (down_interruptible(&et61x251_sysfs_lock))
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENODEV;
        }
 
        value = et61x251_strtou8(buf, len, &count);
        if (!count) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -EINVAL;
        }
 
        err = et61x251_write_reg(cam, value, cam->sysfs.reg);
        if (err) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -EIO;
        }
 
@@ -822,7 +821,7 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
            cam->sysfs.reg, value);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&et61x251_sysfs_lock);
+       mutex_unlock(&et61x251_sysfs_lock);
 
        return count;
 }
@@ -833,12 +832,12 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
        struct et61x251_device* cam;
        ssize_t count;
 
-       if (down_interruptible(&et61x251_sysfs_lock))
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENODEV;
        }
 
@@ -846,7 +845,7 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&et61x251_sysfs_lock);
+       mutex_unlock(&et61x251_sysfs_lock);
 
        return count;
 }
@@ -859,18 +858,18 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
        u8 index;
        ssize_t count;
 
-       if (down_interruptible(&et61x251_sysfs_lock))
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENODEV;
        }
 
        index = et61x251_strtou8(buf, len, &count);
        if (!count) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -EINVAL;
        }
 
@@ -879,7 +878,7 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
        DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&et61x251_sysfs_lock);
+       mutex_unlock(&et61x251_sysfs_lock);
 
        return count;
 }
@@ -891,22 +890,22 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
        ssize_t count;
        int val;
 
-       if (down_interruptible(&et61x251_sysfs_lock))
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENODEV;
        }
 
-       if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) {
-               up(&et61x251_sysfs_lock);
+       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENOSYS;
        }
 
        if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -EIO;
        }
 
@@ -914,7 +913,7 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&et61x251_sysfs_lock);
+       mutex_unlock(&et61x251_sysfs_lock);
 
        return count;
 }
@@ -928,29 +927,29 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
        ssize_t count;
        int err;
 
-       if (down_interruptible(&et61x251_sysfs_lock))
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENODEV;
        }
 
-       if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) {
-               up(&et61x251_sysfs_lock);
+       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
+               mutex_unlock(&et61x251_sysfs_lock);
                return -ENOSYS;
        }
 
        value = et61x251_strtou8(buf, len, &count);
        if (!count) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -EINVAL;
        }
 
        err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
        if (err) {
-               up(&et61x251_sysfs_lock);
+               mutex_unlock(&et61x251_sysfs_lock);
                return -EIO;
        }
 
@@ -958,7 +957,7 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
            cam->sysfs.i2c_reg, value);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&et61x251_sysfs_lock);
+       mutex_unlock(&et61x251_sysfs_lock);
 
        return count;
 }
@@ -980,7 +979,7 @@ static void et61x251_create_sysfs(struct et61x251_device* cam)
 
        video_device_create_file(v4ldev, &class_device_attr_reg);
        video_device_create_file(v4ldev, &class_device_attr_val);
-       if (cam->sensor && cam->sensor->sysfs_ops) {
+       if (cam->sensor.sysfs_ops) {
                video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
                video_device_create_file(v4ldev, &class_device_attr_i2c_val);
        }
@@ -1048,7 +1047,7 @@ static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
 static int
 et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
 {
-       struct et61x251_sensor* s = cam->sensor;
+       struct et61x251_sensor* s = &cam->sensor;
        u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
                           s->active_pixel.left),
            fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
@@ -1076,7 +1075,7 @@ et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
 
 static int et61x251_init(struct et61x251_device* cam)
 {
-       struct et61x251_sensor* s = cam->sensor;
+       struct et61x251_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        struct v4l2_queryctrl *qctrl;
        struct v4l2_rect* rect;
@@ -1143,7 +1142,7 @@ static int et61x251_init(struct et61x251_device* cam)
        }
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_MUTEX(&cam->fileop_sem);
+               mutex_init(&cam->fileop_mutex);
                spin_lock_init(&cam->queue_lock);
                init_waitqueue_head(&cam->wait_frame);
                init_waitqueue_head(&cam->wait_stream);
@@ -1161,13 +1160,15 @@ static int et61x251_init(struct et61x251_device* cam)
 
 static void et61x251_release_resources(struct et61x251_device* cam)
 {
-       down(&et61x251_sysfs_lock);
+       mutex_lock(&et61x251_sysfs_lock);
 
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
 
-       up(&et61x251_sysfs_lock);
+       usb_put_dev(cam->usbdev);
+
+       mutex_unlock(&et61x251_sysfs_lock);
 
        kfree(cam->control_buffer);
 }
@@ -1188,7 +1189,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (down_interruptible(&cam->dev_sem)) {
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
                up_read(&et61x251_disconnect);
                return -ERESTARTSYS;
        }
@@ -1200,7 +1201,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                err = wait_event_interruptible_exclusive(cam->open,
                                                  cam->state & DEV_DISCONNECTED
                                                         || !cam->users);
@@ -1212,7 +1213,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
                        up_read(&et61x251_disconnect);
                        return -ENODEV;
                }
-               down(&cam->dev_sem);
+               mutex_lock(&cam->dev_mutex);
        }
 
 
@@ -1240,7 +1241,7 @@ static int et61x251_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
        up_read(&et61x251_disconnect);
        return err;
 }
@@ -1250,7 +1251,7 @@ static int et61x251_release(struct inode* inode, struct file* filp)
 {
        struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
 
-       down(&cam->dev_sem); /* prevent disconnect() to be called */
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
 
        et61x251_stop_transfer(cam);
 
@@ -1258,7 +1259,7 @@ static int et61x251_release(struct inode* inode, struct file* filp)
 
        if (cam->state & DEV_DISCONNECTED) {
                et61x251_release_resources(cam);
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                kfree(cam);
                return 0;
        }
@@ -1268,7 +1269,7 @@ static int et61x251_release(struct inode* inode, struct file* filp)
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        return 0;
 }
@@ -1281,28 +1282,29 @@ et61x251_read(struct file* filp, char __user * buf,
        struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
        struct et61x251_frame_t* f, * i;
        unsigned long lock_flags;
+       long timeout;
        int err = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
        if (cam->io == IO_MMAP) {
                DBG(3, "Close and open the device again to choose the read "
                       "method");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
@@ -1310,7 +1312,7 @@ et61x251_read(struct file* filp, char __user * buf,
                if (!et61x251_request_buffers(cam, cam->nreadbuffers,
                                              IO_READ)) {
                        DBG(1, "read() failed, not enough memory");
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -ENOMEM;
                }
                cam->io = IO_READ;
@@ -1324,30 +1326,32 @@ et61x251_read(struct file* filp, char __user * buf,
        }
 
        if (!count) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return 0;
        }
 
        if (list_empty(&cam->outqueue)) {
                if (filp->f_flags & O_NONBLOCK) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EAGAIN;
                }
-               err = wait_event_interruptible
-                     ( cam->wait_frame,
-                       (!list_empty(&cam->outqueue)) ||
-                       (cam->state & DEV_DISCONNECTED) ||
-                       (cam->state & DEV_MISCONFIGURED) );
-               if (err) {
-                       up(&cam->fileop_sem);
-                       return err;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
                }
                if (cam->state & DEV_DISCONNECTED) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -ENODEV;
                }
-               if (cam->state & DEV_MISCONFIGURED) {
-                       up(&cam->fileop_sem);
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EIO;
                }
        }
@@ -1375,7 +1379,7 @@ exit:
        PDBGG("Frame #%lu, bytes read: %zu",
              (unsigned long)f->buf.index, count);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return err ? err : count;
 }
@@ -1388,7 +1392,7 @@ static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
        unsigned long lock_flags;
        unsigned int mask = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return POLLERR;
 
        if (cam->state & DEV_DISCONNECTED) {
@@ -1426,12 +1430,12 @@ static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
        if (!list_empty(&cam->outqueue))
                mask |= POLLIN | POLLRDNORM;
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return mask;
 
 error:
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
        return POLLERR;
 }
 
@@ -1465,25 +1469,25 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
        void *pos;
        u32 i;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
        if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
            size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
@@ -1492,7 +1496,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
                        break;
        }
        if (i == cam->nbuffers) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
@@ -1502,7 +1506,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
        pos = cam->frame[i].bufmem;
        while (size > 0) { /* size is page-aligned */
                if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -1515,7 +1519,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
 
        et61x251_vm_open(vma);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return 0;
 }
@@ -1557,6 +1561,7 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
 
        memset(&i, 0, sizeof(i));
        strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
 
        if (copy_to_user(arg, &i, sizeof(i)))
                return -EFAULT;
@@ -1566,7 +1571,19 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
 
 
 static int
-et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg)
+et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
 {
        int index;
 
@@ -1583,7 +1600,7 @@ et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg)
 static int
 et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
 {
-       struct et61x251_sensor* s = cam->sensor;
+       struct et61x251_sensor* s = &cam->sensor;
        struct v4l2_queryctrl qc;
        u8 i;
 
@@ -1605,7 +1622,7 @@ et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
 static int
 et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
 {
-       struct et61x251_sensor* s = cam->sensor;
+       struct et61x251_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        int err = 0;
        u8 i;
@@ -1637,7 +1654,7 @@ exit:
 static int
 et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
 {
-       struct et61x251_sensor* s = cam->sensor;
+       struct et61x251_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        u8 i;
        int err = 0;
@@ -1650,6 +1667,8 @@ et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
 
        for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
                if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
                        if (ctrl.value < s->qctrl[i].minimum ||
                            ctrl.value > s->qctrl[i].maximum)
                                return -ERANGE;
@@ -1669,7 +1688,7 @@ et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
 static int
 et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
 {
-       struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
 
        cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        cc->pixelaspect.numerator = 1;
@@ -1685,7 +1704,7 @@ et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
 static int
 et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
 {
-       struct et61x251_sensor* s = cam->sensor;
+       struct et61x251_sensor* s = &cam->sensor;
        struct v4l2_crop crop = {
                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
        };
@@ -1702,7 +1721,7 @@ et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
 static int
 et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
 {
-       struct et61x251_sensor* s = cam->sensor;
+       struct et61x251_sensor* s = &cam->sensor;
        struct v4l2_crop crop;
        struct v4l2_rect* rect;
        struct v4l2_rect* bounds = &(s->cropcap.bounds);
@@ -1843,7 +1862,7 @@ static int
 et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
 {
        struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
 
        if (copy_from_user(&format, arg, sizeof(format)))
                return -EFAULT;
@@ -1868,7 +1887,7 @@ static int
 et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
                           void __user * arg)
 {
-       struct et61x251_sensor* s = cam->sensor;
+       struct et61x251_sensor* s = &cam->sensor;
        struct v4l2_format format;
        struct v4l2_pix_format* pix;
        struct v4l2_pix_format* pfmt = &(s->pix_format);
@@ -2155,7 +2174,7 @@ et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
        struct v4l2_buffer b;
        struct et61x251_frame_t *f;
        unsigned long lock_flags;
-       int err = 0;
+       long timeout;
 
        if (copy_from_user(&b, arg, sizeof(b)))
                return -EFAULT;
@@ -2168,16 +2187,18 @@ et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
                        return -EINVAL;
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
-               err = wait_event_interruptible
-                     ( cam->wait_frame,
-                       (!list_empty(&cam->outqueue)) ||
-                       (cam->state & DEV_DISCONNECTED) ||
-                       (cam->state & DEV_MISCONFIGURED) );
-               if (err)
-                       return err;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
                if (cam->state & DEV_DISCONNECTED)
                        return -ENODEV;
-               if (cam->state & DEV_MISCONFIGURED)
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
                        return -EIO;
        }
 
@@ -2309,8 +2330,10 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
                return et61x251_vidioc_enuminput(cam, arg);
 
        case VIDIOC_G_INPUT:
+               return et61x251_vidioc_g_input(cam, arg);
+
        case VIDIOC_S_INPUT:
-               return et61x251_vidioc_gs_input(cam, arg);
+               return et61x251_vidioc_s_input(cam, arg);
 
        case VIDIOC_QUERYCTRL:
                return et61x251_vidioc_query_ctrl(cam, arg);
@@ -2393,19 +2416,19 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp,
        struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
        int err = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
@@ -2413,7 +2436,7 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp,
 
        err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return err;
 }
@@ -2459,7 +2482,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       init_MUTEX(&cam->dev_sem);
+       mutex_init(&cam->dev_mutex);
 
        DBG(2, "ET61X[12]51 PC Camera Controller detected "
               "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
@@ -2470,8 +2493,8 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        break;
        }
 
-       if (!err && cam->sensor)
-               DBG(2, "%s image sensor detected", cam->sensor->name);
+       if (!err)
+               DBG(2, "%s image sensor detected", cam->sensor.name);
        else {
                DBG(1, "No supported image sensor detected");
                err = -ENODEV;
@@ -2492,7 +2515,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       down(&cam->dev_sem);
+       mutex_lock(&cam->dev_mutex);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -2502,13 +2525,14 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                goto fail;
        }
 
        DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
        cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
 
        dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
@@ -2519,7 +2543,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        usb_set_intfdata(intf, cam);
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        return 0;
 
@@ -2543,7 +2567,7 @@ static void et61x251_usb_disconnect(struct usb_interface* intf)
 
        down_write(&et61x251_disconnect);
 
-       down(&cam->dev_sem);
+       mutex_lock(&cam->dev_mutex);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
@@ -2557,13 +2581,14 @@ static void et61x251_usb_disconnect(struct usb_interface* intf)
                et61x251_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
-               wake_up_interruptible(&cam->wait_stream);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
        } else {
                cam->state |= DEV_DISCONNECTED;
                et61x251_release_resources(cam);
        }
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        if (!cam->users)
                kfree(cam);
index b9df910..56841ae 100644 (file)
@@ -42,6 +42,9 @@ static int (*et61x251_sensor_table[])(struct et61x251_device*) = {            \
        NULL,                                                                 \
 };
 
+extern struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
+
 extern void
 et61x251_attach_sensor(struct et61x251_device* cam,
                        struct et61x251_sensor* sensor);
@@ -105,8 +108,6 @@ struct et61x251_sensor {
        int (*set_pix_format)(struct et61x251_device* cam,
                              const struct v4l2_pix_format* pix);
 
-       const struct usb_device* usbdev;
-
        /* Private */
        struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
        struct v4l2_rect _rect;
index 65f1ae9..3998d76 100644 (file)
@@ -126,12 +126,16 @@ static struct et61x251_sensor tas5130d1b = {
 
 int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
 {
-       /* This sensor has no identifiers, so let's attach it anyway */
-       et61x251_attach_sensor(cam, &tas5130d1b);
+       const struct usb_device_id tas5130d1b_id_table[] = {
+               { USB_DEVICE(0x102c, 0x6251), },
+               { }
+       };
 
        /* Sensor detection is based on USB pid/vid */
-       if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6251)
+       if (!et61x251_match_id(cam, tas5130d1b_id_table))
                return -ENODEV;
 
+       et61x251_attach_sensor(cam, &tas5130d1b);
+
        return 0;
 }
index 51e9cc0..da44579 100644 (file)
@@ -365,14 +365,14 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 
        PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
-       down(&ov->cbuf_lock);
+       mutex_lock(&ov->cbuf_lock);
        ov->cbuf[0] = value;
        rc = usb_control_msg(ov->dev,
                             usb_sndctrlpipe(ov->dev, 0),
                             (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
                             USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                             0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-       up(&ov->cbuf_lock);
+       mutex_unlock(&ov->cbuf_lock);
 
        if (rc < 0)
                err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
@@ -387,7 +387,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
 {
        int rc;
 
-       down(&ov->cbuf_lock);
+       mutex_lock(&ov->cbuf_lock);
        rc = usb_control_msg(ov->dev,
                             usb_rcvctrlpipe(ov->dev, 0),
                             (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
@@ -401,7 +401,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
                PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
        }
 
-       up(&ov->cbuf_lock);
+       mutex_unlock(&ov->cbuf_lock);
 
        return rc;
 }
@@ -444,7 +444,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
 
        PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
 
-       down(&ov->cbuf_lock);
+       mutex_lock(&ov->cbuf_lock);
 
        *((__le32 *)ov->cbuf) = __cpu_to_le32(val);
 
@@ -453,7 +453,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
                             1 /* REG_IO */,
                             USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                             0, (__u16)reg, ov->cbuf, n, 1000);
-       up(&ov->cbuf_lock);
+       mutex_unlock(&ov->cbuf_lock);
 
        if (rc < 0)
                err("reg write multiple: error %d: %s", rc,
@@ -768,14 +768,14 @@ i2c_r(struct usb_ov511 *ov, unsigned char reg)
 {
        int rc;
 
-       down(&ov->i2c_lock);
+       mutex_lock(&ov->i2c_lock);
 
        if (ov->bclass == BCL_OV518)
                rc = ov518_i2c_read_internal(ov, reg);
        else
                rc = ov511_i2c_read_internal(ov, reg);
 
-       up(&ov->i2c_lock);
+       mutex_unlock(&ov->i2c_lock);
 
        return rc;
 }
@@ -785,14 +785,14 @@ i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
        int rc;
 
-       down(&ov->i2c_lock);
+       mutex_lock(&ov->i2c_lock);
 
        if (ov->bclass == BCL_OV518)
                rc = ov518_i2c_write_internal(ov, reg, value);
        else
                rc = ov511_i2c_write_internal(ov, reg, value);
 
-       up(&ov->i2c_lock);
+       mutex_unlock(&ov->i2c_lock);
 
        return rc;
 }
@@ -842,9 +842,9 @@ i2c_w_mask(struct usb_ov511 *ov,
 {
        int rc;
 
-       down(&ov->i2c_lock);
+       mutex_lock(&ov->i2c_lock);
        rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-       up(&ov->i2c_lock);
+       mutex_unlock(&ov->i2c_lock);
 
        return rc;
 }
@@ -880,7 +880,7 @@ i2c_w_slave(struct usb_ov511 *ov,
 {
        int rc = 0;
 
-       down(&ov->i2c_lock);
+       mutex_lock(&ov->i2c_lock);
 
        /* Set new slave IDs */
        rc = i2c_set_slave_internal(ov, slave);
@@ -894,7 +894,7 @@ out:
        if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
                err("Couldn't restore primary I2C slave");
 
-       up(&ov->i2c_lock);
+       mutex_unlock(&ov->i2c_lock);
        return rc;
 }
 
@@ -906,7 +906,7 @@ i2c_r_slave(struct usb_ov511 *ov,
 {
        int rc;
 
-       down(&ov->i2c_lock);
+       mutex_lock(&ov->i2c_lock);
 
        /* Set new slave IDs */
        rc = i2c_set_slave_internal(ov, slave);
@@ -923,7 +923,7 @@ out:
        if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
                err("Couldn't restore primary I2C slave");
 
-       up(&ov->i2c_lock);
+       mutex_unlock(&ov->i2c_lock);
        return rc;
 }
 
@@ -933,7 +933,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
 {
        int rc;
 
-       down(&ov->i2c_lock);
+       mutex_lock(&ov->i2c_lock);
 
        rc = i2c_set_slave_internal(ov, sid);
        if (rc < 0)
@@ -942,7 +942,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
        // FIXME: Is this actually necessary?
        rc = ov51x_reset(ov, OV511_RESET_NOREGS);
 out:
-       up(&ov->i2c_lock);
+       mutex_unlock(&ov->i2c_lock);
        return rc;
 }
 
@@ -3832,7 +3832,7 @@ ov51x_alloc(struct usb_ov511 *ov)
        const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
 
        PDEBUG(4, "entered");
-       down(&ov->buf_lock);
+       mutex_lock(&ov->buf_lock);
 
        if (ov->buf_state == BUF_ALLOCATED)
                goto out;
@@ -3879,12 +3879,12 @@ ov51x_alloc(struct usb_ov511 *ov)
 
        ov->buf_state = BUF_ALLOCATED;
 out:
-       up(&ov->buf_lock);
+       mutex_unlock(&ov->buf_lock);
        PDEBUG(4, "leaving");
        return 0;
 error:
        ov51x_do_dealloc(ov);
-       up(&ov->buf_lock);
+       mutex_unlock(&ov->buf_lock);
        PDEBUG(4, "errored");
        return -ENOMEM;
 }
@@ -3893,9 +3893,9 @@ static void
 ov51x_dealloc(struct usb_ov511 *ov)
 {
        PDEBUG(4, "entered");
-       down(&ov->buf_lock);
+       mutex_lock(&ov->buf_lock);
        ov51x_do_dealloc(ov);
-       up(&ov->buf_lock);
+       mutex_unlock(&ov->buf_lock);
        PDEBUG(4, "leaving");
 }
 
@@ -3914,7 +3914,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
 
        PDEBUG(4, "opening");
 
-       down(&ov->lock);
+       mutex_lock(&ov->lock);
 
        err = -EBUSY;
        if (ov->user)
@@ -3958,7 +3958,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
                ov51x_led_control(ov, 1);
 
 out:
-       up(&ov->lock);
+       mutex_unlock(&ov->lock);
        return err;
 }
 
@@ -3970,7 +3970,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
 
        PDEBUG(4, "ov511_close");
 
-       down(&ov->lock);
+       mutex_lock(&ov->lock);
 
        ov->user--;
        ov51x_stop_isoc(ov);
@@ -3981,15 +3981,15 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
        if (ov->dev)
                ov51x_dealloc(ov);
 
-       up(&ov->lock);
+       mutex_unlock(&ov->lock);
 
        /* Device unplugged while open. Only a minimum of unregistration is done
         * here; the disconnect callback already did the rest. */
        if (!ov->dev) {
-               down(&ov->cbuf_lock);
+               mutex_lock(&ov->cbuf_lock);
                kfree(ov->cbuf);
                ov->cbuf = NULL;
-               up(&ov->cbuf_lock);
+               mutex_unlock(&ov->cbuf_lock);
 
                ov51x_dealloc(ov);
                kfree(ov);
@@ -4449,12 +4449,12 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
        struct usb_ov511 *ov = video_get_drvdata(vdev);
        int rc;
 
-       if (down_interruptible(&ov->lock))
+       if (mutex_lock_interruptible(&ov->lock))
                return -EINTR;
 
        rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
 
-       up(&ov->lock);
+       mutex_unlock(&ov->lock);
        return rc;
 }
 
@@ -4468,7 +4468,7 @@ ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
        int i, rc = 0, frmx = -1;
        struct ov511_frame *frame;
 
-       if (down_interruptible(&ov->lock))
+       if (mutex_lock_interruptible(&ov->lock))
                return -EINTR;
 
        PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
@@ -4604,11 +4604,11 @@ restart:
 
        PDEBUG(4, "read finished, returning %ld (sweet)", count);
 
-       up(&ov->lock);
+       mutex_unlock(&ov->lock);
        return count;
 
 error:
-       up(&ov->lock);
+       mutex_unlock(&ov->lock);
        return rc;
 }
 
@@ -4631,14 +4631,14 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
                      + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
                return -EINVAL;
 
-       if (down_interruptible(&ov->lock))
+       if (mutex_lock_interruptible(&ov->lock))
                return -EINTR;
 
        pos = (unsigned long)ov->fbuf;
        while (size > 0) {
                page = vmalloc_to_pfn((void *)pos);
                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       up(&ov->lock);
+                       mutex_unlock(&ov->lock);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -4649,7 +4649,7 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
                        size = 0;
        }
 
-       up(&ov->lock);
+       mutex_unlock(&ov->lock);
        return 0;
 }
 
@@ -5639,7 +5639,7 @@ static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
 static ssize_t show_exposure(struct class_device *cd, char *buf)
 {
        struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned char exp;
+       unsigned char exp = 0;
 
        if (!ov->dev)
                return -ENODEV;
@@ -5686,13 +5686,11 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
        if (idesc->bInterfaceSubClass != 0x00)
                return -ENODEV;
 
-       if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
+       if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
                err("couldn't kmalloc ov struct");
                goto error_out;
        }
 
-       memset(ov, 0, sizeof(*ov));
-
        ov->dev = dev;
        ov->iface = idesc->bInterfaceNumber;
        ov->led_policy = led;
@@ -5738,11 +5736,10 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        init_waitqueue_head(&ov->wq);
 
-       init_MUTEX(&ov->lock);  /* to 1 == available */
-       init_MUTEX(&ov->buf_lock);
-       init_MUTEX(&ov->param_lock);
-       init_MUTEX(&ov->i2c_lock);
-       init_MUTEX(&ov->cbuf_lock);
+       mutex_init(&ov->lock);  /* to 1 == available */
+       mutex_init(&ov->buf_lock);
+       mutex_init(&ov->i2c_lock);
+       mutex_init(&ov->cbuf_lock);
 
        ov->buf_state = BUF_NOT_ALLOCATED;
 
@@ -5833,10 +5830,10 @@ error:
        }
 
        if (ov->cbuf) {
-               down(&ov->cbuf_lock);
+               mutex_lock(&ov->cbuf_lock);
                kfree(ov->cbuf);
                ov->cbuf = NULL;
-               up(&ov->cbuf_lock);
+               mutex_unlock(&ov->cbuf_lock);
        }
 
        kfree(ov);
@@ -5881,10 +5878,10 @@ ov51x_disconnect(struct usb_interface *intf)
 
        /* Free the memory */
        if (ov && !ov->user) {
-               down(&ov->cbuf_lock);
+               mutex_lock(&ov->cbuf_lock);
                kfree(ov->cbuf);
                ov->cbuf = NULL;
-               up(&ov->cbuf_lock);
+               mutex_unlock(&ov->cbuf_lock);
 
                ov51x_dealloc(ov);
                kfree(ov);
index 086509a..bce9b36 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/videodev.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #define OV511_DEBUG    /* Turn on debug messages */
 
@@ -435,7 +436,7 @@ struct usb_ov511 {
 
        int led_policy;         /* LED: off|on|auto; OV511+ only */
 
-       struct semaphore lock;  /* Serializes user-accessible operations */
+       struct mutex lock;      /* Serializes user-accessible operations */
        int user;               /* user count for exclusive use */
 
        int streaming;          /* Are we streaming Isochronous? */
@@ -473,11 +474,9 @@ struct usb_ov511 {
        int packet_size;        /* Frame size per isoc desc */
        int packet_numbering;   /* Is ISO frame numbering enabled? */
 
-       struct semaphore param_lock;    /* params lock for this camera */
-
        /* Framebuffer/sbuf management */
        int buf_state;
-       struct semaphore buf_lock;
+       struct mutex buf_lock;
 
        struct ov51x_decomp_ops *decomp_ops;
 
@@ -494,12 +493,12 @@ struct usb_ov511 {
        int pal;                /* Device is designed for PAL resolution */
 
        /* I2C interface */
-       struct semaphore i2c_lock;        /* Protect I2C controller regs */
+       struct mutex i2c_lock;    /* Protect I2C controller regs */
        unsigned char primary_i2c_slave;  /* I2C write id of sensor */
 
        /* Control transaction stuff */
        unsigned char *cbuf;            /* Buffer for payload */
-       struct semaphore cbuf_lock;
+       struct mutex cbuf_lock;
 };
 
 /* Used to represent a list of values and their respective symbolic names */
index 3ebb6e9..0398b81 100644 (file)
@@ -41,7 +41,6 @@
 #include <asm/uaccess.h> 
 #endif
 #include <asm/errno.h>
-#include <linux/version.h>
  
 #include "pwc.h"
 #include "pwc-ioctl.h"
index 4f9b0dc..90eb260 100644 (file)
@@ -62,7 +62,6 @@
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/version.h>
 #include <asm/io.h>
 
 #include "pwc.h"
@@ -827,13 +826,10 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        /* Get the current alternate interface, adjust packet size */
        if (!udev->actconfig)
                return -EFAULT;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
-       idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate];
-#else
+
        intf = usb_ifnum_to_if(udev, 0);
        if (intf)
                idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
-#endif
                
        if (!idesc)
                return -EFAULT;
@@ -1871,12 +1867,11 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                Info("Warning: more than 1 configuration available.\n");
 
        /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
-       pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL);
+       pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
        if (pdev == NULL) {
                Err("Oops, could not allocate memory for pwc_device.\n");
                return -ENOMEM;
        }
-       memset(pdev, 0, sizeof(struct pwc_device));
        pdev->type = type_id;
        pdev->vsize = default_size;
        pdev->vframes = default_fps;
index 2ba5622..f03ea7f 100644 (file)
@@ -1157,21 +1157,21 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
        unsigned long size  = vma->vm_end-vma->vm_start;
        unsigned long page, pos;
 
-       down(&se401->lock);
+       mutex_lock(&se401->lock);
 
        if (se401->dev == NULL) {
-               up(&se401->lock);
+               mutex_unlock(&se401->lock);
                return -EIO;
        }
        if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-               up(&se401->lock);
+               mutex_unlock(&se401->lock);
                return -EINVAL;
        }
        pos = (unsigned long)se401->fbuf;
        while (size > 0) {
                page = vmalloc_to_pfn((void *)pos);
                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       up(&se401->lock);
+                       mutex_unlock(&se401->lock);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -1181,7 +1181,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
                else
                        size = 0;
        }
-       up(&se401->lock);
+       mutex_unlock(&se401->lock);
 
         return 0;
 }
@@ -1345,13 +1345,11 @@ static int se401_probe(struct usb_interface *intf,
         /* We found one */
         info("SE401 camera found: %s", camera_name);
 
-        if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+        if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
                 err("couldn't kmalloc se401 struct");
                return -ENOMEM;
         }
 
-        memset(se401, 0, sizeof(*se401));
-
         se401->dev = dev;
         se401->iface = interface->bInterfaceNumber;
         se401->camera_name = camera_name;
@@ -1366,7 +1364,7 @@ static int se401_probe(struct usb_interface *intf,
        memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
        memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
        init_waitqueue_head(&se401->wq);
-       init_MUTEX(&se401->lock);
+       mutex_init(&se401->lock);
        wmb();
 
        if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
index 2e5846f..e88a40d 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #define se401_DEBUG    /* Turn on debug messages */
 
@@ -189,7 +190,7 @@ struct usb_se401 {
        int maxframesize;
        int cframesize;         /* current framesize */
 
-       struct semaphore lock;
+       struct mutex lock;
        int user;               /* user count for exclusive use */
        int removed;            /* device disconnected */
 
index 17d60c1..1d70a62 100644 (file)
@@ -33,7 +33,9 @@
 #include <linux/types.h>
 #include <linux/param.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
 
 #include "sn9c102_sensor.h"
 
@@ -50,6 +52,7 @@
 #define SN9C102_ALTERNATE_SETTING 8
 #define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
 #define SN9C102_CTRL_TIMEOUT      300
+#define SN9C102_FRAME_TIMEOUT     2
 
 /*****************************************************************************/
 
@@ -107,16 +110,17 @@ struct sn9c102_sysfs_attr {
 
 struct sn9c102_module_param {
        u8 force_munmap;
+       u16 frame_timeout;
 };
 
-static DECLARE_MUTEX(sn9c102_sysfs_lock);
+static DEFINE_MUTEX(sn9c102_sysfs_lock);
 static DECLARE_RWSEM(sn9c102_disconnect);
 
 struct sn9c102_device {
        struct video_device* v4ldev;
 
        enum sn9c102_bridge bridge;
-       struct sn9c102_sensor* sensor;
+       struct sn9c102_sensor sensor;
 
        struct usb_device* usbdev;
        struct urb* urb[SN9C102_URBS];
@@ -141,19 +145,28 @@ struct sn9c102_device {
        enum sn9c102_dev_state state;
        u8 users;
 
-       struct semaphore dev_sem, fileop_sem;
+       struct mutex dev_mutex, fileop_mutex;
        spinlock_t queue_lock;
        wait_queue_head_t open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
 
+struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
+{
+       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+               return cam;
+
+       return NULL;
+}
+
+
 void
 sn9c102_attach_sensor(struct sn9c102_device* cam,
                       struct sn9c102_sensor* sensor)
 {
-       cam->sensor = sensor;
-       cam->sensor->usbdev = cam->usbdev;
+       memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
 }
 
 /*****************************************************************************/
@@ -196,7 +209,8 @@ do {                                                                          \
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
index c81397e..4c6cc63 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
-#include <linux/stddef.h>
 #include <linux/compiler.h>
 #include <linux/ioctl.h>
 #include <linux/poll.h>
@@ -49,8 +47,8 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.26"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 26)
+#define SN9C102_MODULE_VERSION  "1:1.27"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
 
 /*****************************************************************************/
 
@@ -89,6 +87,15 @@ MODULE_PARM_DESC(force_munmap,
                  "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                  "\n");
 
+static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+                                       SN9C102_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
+                 "\n");
+
 #ifdef SN9C102_DEBUG
 static unsigned short debug = SN9C102_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
@@ -128,8 +135,8 @@ static u32
 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
                         enum sn9c102_io_method io)
 {
-       struct v4l2_pix_format* p = &(cam->sensor->pix_format);
-       struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
        const size_t imagesize = cam->module_param.force_munmap ||
                                 io == IO_READ ?
                                 (p->width * p->height * p->priv) / 8 :
@@ -449,19 +456,13 @@ sn9c102_i2c_try_write(struct sn9c102_device* cam,
 
 int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
 {
-       if (!cam->sensor)
-               return -1;
-
-       return sn9c102_i2c_try_read(cam, cam->sensor, address);
+       return sn9c102_i2c_try_read(cam, &cam->sensor, address);
 }
 
 
 int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 {
-       if (!cam->sensor)
-               return -1;
-
-       return sn9c102_i2c_try_write(cam, cam->sensor, address, value);
+       return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
 }
 
 /*****************************************************************************/
@@ -505,7 +506,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
        size_t eoflen = sizeof(sn9c102_eof_header_t), i;
        unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
 
-       if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
                return NULL; /* EOF header does not exist in compressed data */
 
        for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
@@ -535,7 +536,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
                if ((*f))
                        (*f)->state = F_QUEUED;
                DBG(3, "Stream interrupted");
-               wake_up_interruptible(&cam->wait_stream);
+               wake_up(&cam->wait_stream);
        }
 
        if (cam->state & DEV_DISCONNECTED)
@@ -553,9 +554,9 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
                (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
                                  frame);
 
-       imagesize = (cam->sensor->pix_format.width *
-                    cam->sensor->pix_format.height *
-                    cam->sensor->pix_format.priv) / 8;
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
 
        soflen = (cam->bridge) == BRIDGE_SN9C103 ?
                                  sizeof(sn9c103_sof_header_t) :
@@ -579,7 +580,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 
 redo:
                sof = sn9c102_find_sof_header(cam, pos, len);
-               if (!sof) {
+               if (likely(!sof)) {
                        eof = sn9c102_find_eof_header(cam, pos, len);
                        if ((*f)->state == F_GRABBING) {
 end_of_frame:
@@ -589,8 +590,9 @@ end_of_frame:
                                        img = (eof > pos) ? eof - pos - 1 : 0;
 
                                if ((*f)->buf.bytesused+img > imagesize) {
-                                       u32 b = (*f)->buf.bytesused + img -
-                                               imagesize;
+                                       u32 b;
+                                       b = (*f)->buf.bytesused + img -
+                                           imagesize;
                                        img = imagesize - (*f)->buf.bytesused;
                                        DBG(3, "Expected EOF not found: "
                                               "video frame cut");
@@ -608,9 +610,10 @@ end_of_frame:
                                (*f)->buf.bytesused += img;
 
                                if ((*f)->buf.bytesused == imagesize ||
-                                   (cam->sensor->pix_format.pixelformat ==
+                                   (cam->sensor.pix_format.pixelformat ==
                                                V4L2_PIX_FMT_SN9C10X && eof)) {
-                                       u32 b = (*f)->buf.bytesused;
+                                       u32 b;
+                                       b = (*f)->buf.bytesused;
                                        (*f)->state = F_DONE;
                                        (*f)->buf.sequence= ++cam->frame_count;
                                        spin_lock(&cam->queue_lock);
@@ -667,7 +670,7 @@ start_of_frame:
                        if (eof && eof < sof)
                                goto end_of_frame; /* (1) */
                        else {
-                               if (cam->sensor->pix_format.pixelformat ==
+                               if (cam->sensor.pix_format.pixelformat ==
                                    V4L2_PIX_FMT_SN9C10X) {
                                        eof = sof - soflen;
                                        goto end_of_frame;
@@ -808,20 +811,21 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
 
 static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
 {
-       int err = 0;
+       long timeout;
 
        cam->stream = STREAM_INTERRUPT;
-       err = wait_event_timeout(cam->wait_stream,
-                                (cam->stream == STREAM_OFF) ||
-                                (cam->state & DEV_DISCONNECTED),
-                                SN9C102_URB_TIMEOUT);
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    SN9C102_URB_TIMEOUT);
        if (cam->state & DEV_DISCONNECTED)
                return -ENODEV;
-       else if (err) {
+       else if (cam->stream != STREAM_OFF) {
                cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "The camera is misconfigured. To use it, close and "
-                      "open /dev/video%d again.", cam->v4ldev->minor);
-               return err;
+               DBG(1, "URB timeout reached. The camera is misconfigured. "
+                      "To use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
        }
 
        return 0;
@@ -866,18 +870,18 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
        struct sn9c102_device* cam;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        count = sprintf(buf, "%u\n", cam->sysfs.reg);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 } 
@@ -890,18 +894,18 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
        u8 index;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        index = sn9c102_strtou8(buf, len, &count);
        if (index > 0x1f || !count) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
@@ -910,7 +914,7 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
        DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -922,17 +926,17 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
        ssize_t count;
        int val;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EIO;
        }
 
@@ -940,7 +944,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 } 
@@ -954,24 +958,24 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
        ssize_t count;
        int err;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        value = sn9c102_strtou8(buf, len, &count);
        if (!count) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
        err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
        if (err) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EIO;
        }
 
@@ -979,7 +983,7 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
            cam->sysfs.reg, value);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -990,12 +994,12 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
        struct sn9c102_device* cam;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
@@ -1003,7 +1007,7 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -1016,18 +1020,18 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
        u8 index;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        index = sn9c102_strtou8(buf, len, &count);
        if (!count) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
@@ -1036,7 +1040,7 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
        DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -1048,22 +1052,22 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
        ssize_t count;
        int val;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
-       if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) {
-               up(&sn9c102_sysfs_lock);
+       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENOSYS;
        }
 
        if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EIO;
        }
 
@@ -1071,7 +1075,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
 
        DBG(3, "Read bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 } 
@@ -1085,29 +1089,29 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
        ssize_t count;
        int err;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
-       if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) {
-               up(&sn9c102_sysfs_lock);
+       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENOSYS;
        }
 
        value = sn9c102_strtou8(buf, len, &count);
        if (!count) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EINVAL;
        }
 
        err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
        if (err) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -EIO;
        }
 
@@ -1115,7 +1119,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
            cam->sysfs.i2c_reg, value);
        DBG(3, "Written bytes: %zd", count);
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        return count;
 }
@@ -1130,18 +1134,18 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
        u8 value;
        ssize_t count;
 
-       if (down_interruptible(&sn9c102_sysfs_lock))
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
                return -ERESTARTSYS;
 
        cam = video_get_drvdata(to_video_device(cd));
        if (!cam) {
-               up(&sn9c102_sysfs_lock);
+               mutex_unlock(&sn9c102_sysfs_lock);
                return -ENODEV;
        }
 
        bridge = cam->bridge;
 
-       up(&sn9c102_sysfs_lock);
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        value = sn9c102_strtou8(buf, len, &count);
        if (!count)
@@ -1249,7 +1253,7 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
                video_device_create_file(v4ldev, &class_device_attr_blue);
                video_device_create_file(v4ldev, &class_device_attr_red);
        }
-       if (cam->sensor && cam->sensor->sysfs_ops) {
+       if (cam->sensor.sysfs_ops) {
                video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
                video_device_create_file(v4ldev, &class_device_attr_i2c_val);
        }
@@ -1312,7 +1316,7 @@ static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
 
 static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
           v_start = (u8)(rect->top - s->cropcap.bounds.top),
           h_size = (u8)(rect->width / 16),
@@ -1335,7 +1339,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
 
 static int sn9c102_init(struct sn9c102_device* cam)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        struct v4l2_queryctrl *qctrl;
        struct v4l2_rect* rect;
@@ -1404,7 +1408,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
        }
 
        if (!(cam->state & DEV_INITIALIZED)) {
-               init_MUTEX(&cam->fileop_sem);
+               mutex_init(&cam->fileop_mutex);
                spin_lock_init(&cam->queue_lock);
                init_waitqueue_head(&cam->wait_frame);
                init_waitqueue_head(&cam->wait_stream);
@@ -1422,13 +1426,15 @@ static int sn9c102_init(struct sn9c102_device* cam)
 
 static void sn9c102_release_resources(struct sn9c102_device* cam)
 {
-       down(&sn9c102_sysfs_lock);
+       mutex_lock(&sn9c102_sysfs_lock);
 
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
 
-       up(&sn9c102_sysfs_lock);
+       usb_put_dev(cam->usbdev);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
 
        kfree(cam->control_buffer);
 }
@@ -1449,7 +1455,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
 
        cam = video_get_drvdata(video_devdata(filp));
 
-       if (down_interruptible(&cam->dev_sem)) {
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
                up_read(&sn9c102_disconnect);
                return -ERESTARTSYS;
        }
@@ -1461,7 +1467,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
                        err = -EWOULDBLOCK;
                        goto out;
                }
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                err = wait_event_interruptible_exclusive(cam->open,
                                                  cam->state & DEV_DISCONNECTED
                                                         || !cam->users);
@@ -1473,7 +1479,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
                        up_read(&sn9c102_disconnect);
                        return -ENODEV;
                }
-               down(&cam->dev_sem);
+               mutex_lock(&cam->dev_mutex);
        }
 
 
@@ -1501,7 +1507,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
        up_read(&sn9c102_disconnect);
        return err;
 }
@@ -1511,7 +1517,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 {
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
 
-       down(&cam->dev_sem); /* prevent disconnect() to be called */
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
 
        sn9c102_stop_transfer(cam);
 
@@ -1519,7 +1525,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 
        if (cam->state & DEV_DISCONNECTED) {
                sn9c102_release_resources(cam);
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                kfree(cam);
                return 0;
        }
@@ -1529,7 +1535,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 
        DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        return 0;
 }
@@ -1541,35 +1547,36 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
        struct sn9c102_frame_t* f, * i;
        unsigned long lock_flags;
+       long timeout;
        int err = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
        if (cam->io == IO_MMAP) {
                DBG(3, "Close and open the device again to choose "
                       "the read method");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
        if (cam->io == IO_NONE) {
                if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
                        DBG(1, "read() failed, not enough memory");
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -ENOMEM;
                }
                cam->io = IO_READ;
@@ -1583,30 +1590,32 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
        }
 
        if (!count) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return 0;
        }
 
        if (list_empty(&cam->outqueue)) {
                if (filp->f_flags & O_NONBLOCK) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EAGAIN;
                }
-               err = wait_event_interruptible
-                     ( cam->wait_frame, 
-                       (!list_empty(&cam->outqueue)) ||
-                       (cam->state & DEV_DISCONNECTED) ||
-                       (cam->state & DEV_MISCONFIGURED) );
-               if (err) {
-                       up(&cam->fileop_sem);
-                       return err;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
                }
                if (cam->state & DEV_DISCONNECTED) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -ENODEV;
                }
-               if (cam->state & DEV_MISCONFIGURED) {
-                       up(&cam->fileop_sem);
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EIO;
                }
        }
@@ -1634,7 +1643,7 @@ exit:
        PDBGG("Frame #%lu, bytes read: %zu",
              (unsigned long)f->buf.index, count);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return count;
 }
@@ -1647,7 +1656,7 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
        unsigned long lock_flags;
        unsigned int mask = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return POLLERR;
 
        if (cam->state & DEV_DISCONNECTED) {
@@ -1685,12 +1694,12 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
        if (!list_empty(&cam->outqueue))
                mask |= POLLIN | POLLRDNORM;
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return mask;
 
 error:
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
        return POLLERR;
 }
 
@@ -1724,25 +1733,25 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
        void *pos;
        u32 i;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
        if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
            size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
@@ -1751,7 +1760,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
                        break;
        }
        if (i == cam->nbuffers) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EINVAL;
        }
 
@@ -1761,7 +1770,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
        pos = cam->frame[i].bufmem;
        while (size > 0) { /* size is page-aligned */
                if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       up(&cam->fileop_sem);
+                       mutex_unlock(&cam->fileop_mutex);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -1774,7 +1783,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 
        sn9c102_vm_open(vma);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return 0;
 }
@@ -1816,6 +1825,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
 
        memset(&i, 0, sizeof(i));
        strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
 
        if (copy_to_user(arg, &i, sizeof(i)))
                return -EFAULT;
@@ -1825,7 +1835,19 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
 
 
 static int
-sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
 {
        int index;
 
@@ -1842,7 +1864,7 @@ sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_queryctrl qc;
        u8 i;
 
@@ -1864,7 +1886,7 @@ sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        int err = 0;
        u8 i;
@@ -1896,7 +1918,7 @@ exit:
 static int
 sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        u8 i;
        int err = 0;
@@ -1909,6 +1931,8 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
 
        for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
                if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
                        if (ctrl.value < s->qctrl[i].minimum ||
                            ctrl.value > s->qctrl[i].maximum)
                                return -ERANGE;
@@ -1931,7 +1955,7 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
 {
-       struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
 
        cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        cc->pixelaspect.numerator = 1;
@@ -1947,7 +1971,7 @@ sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_crop crop = {
                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
        };
@@ -1964,7 +1988,7 @@ sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
 static int
 sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_crop crop;
        struct v4l2_rect* rect;
        struct v4l2_rect* bounds = &(s->cropcap.bounds);
@@ -2105,7 +2129,7 @@ static int
 sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
 {
        struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
 
        if (copy_from_user(&format, arg, sizeof(format)))
                return -EFAULT;
@@ -2130,7 +2154,7 @@ static int
 sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
                          void __user * arg)
 {
-       struct sn9c102_sensor* s = cam->sensor;
+       struct sn9c102_sensor* s = &cam->sensor;
        struct v4l2_format format;
        struct v4l2_pix_format* pix;
        struct v4l2_pix_format* pfmt = &(s->pix_format);
@@ -2417,7 +2441,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
        struct v4l2_buffer b;
        struct sn9c102_frame_t *f;
        unsigned long lock_flags;
-       int err = 0;
+       long timeout;
 
        if (copy_from_user(&b, arg, sizeof(b)))
                return -EFAULT;
@@ -2430,16 +2454,18 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
                        return -EINVAL;
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
-               err = wait_event_interruptible
-                     ( cam->wait_frame,
-                       (!list_empty(&cam->outqueue)) ||
-                       (cam->state & DEV_DISCONNECTED) ||
-                       (cam->state & DEV_MISCONFIGURED) );
-               if (err)
-                       return err;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
                if (cam->state & DEV_DISCONNECTED)
                        return -ENODEV;
-               if (cam->state & DEV_MISCONFIGURED)
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
                        return -EIO;
        }
 
@@ -2571,8 +2597,10 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
                return sn9c102_vidioc_enuminput(cam, arg);
 
        case VIDIOC_G_INPUT:
+               return sn9c102_vidioc_g_input(cam, arg);
+
        case VIDIOC_S_INPUT:
-               return sn9c102_vidioc_gs_input(cam, arg);
+               return sn9c102_vidioc_s_input(cam, arg);
 
        case VIDIOC_QUERYCTRL:
                return sn9c102_vidioc_query_ctrl(cam, arg);
@@ -2655,19 +2683,19 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
        int err = 0;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
                DBG(1, "Device not present");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
                DBG(1, "The camera is misconfigured. Close and open it "
                       "again.");
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
@@ -2675,7 +2703,7 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
 
        err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
 
        return err;
 }
@@ -2722,7 +2750,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                goto fail;
        }
 
-       init_MUTEX(&cam->dev_sem);
+       mutex_init(&cam->dev_mutex);
 
        r = sn9c102_read_reg(cam, 0x00);
        if (r < 0 || r != 0x10) {
@@ -2752,10 +2780,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        break;
        }
 
-       if (!err && cam->sensor) {
-               DBG(2, "%s image sensor detected", cam->sensor->name);
+       if (!err) {
+               DBG(2, "%s image sensor detected", cam->sensor.name);
                DBG(3, "Support for %s maintained by %s",
-                   cam->sensor->name, cam->sensor->maintainer);
+                   cam->sensor.name, cam->sensor.maintainer);
        } else {
                DBG(1, "No supported image sensor detected");
                err = -ENODEV;
@@ -2776,7 +2804,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        cam->v4ldev->release = video_device_release;
        video_set_drvdata(cam->v4ldev, cam);
 
-       down(&cam->dev_sem);
+       mutex_lock(&cam->dev_mutex);
 
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
@@ -2786,13 +2814,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                        DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                goto fail;
        }
 
        DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
        cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
 
        dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
@@ -2803,7 +2832,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
        usb_set_intfdata(intf, cam);
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        return 0;
 
@@ -2827,7 +2856,7 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
 
        down_write(&sn9c102_disconnect);
 
-       down(&cam->dev_sem); 
+       mutex_lock(&cam->dev_mutex);
 
        DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
@@ -2841,13 +2870,14 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
                sn9c102_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
-               wake_up_interruptible(&cam->wait_stream);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
        } else {
                cam->state |= DEV_DISCONNECTED;
                sn9c102_release_resources(cam);
        }
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
 
        if (!cam->users)
                kfree(cam);
index 4a36519..42852b7 100644 (file)
@@ -34,8 +34,8 @@ static int ov7630_init(struct sn9c102_device* cam)
        err += sn9c102_write_reg(cam, 0x0f, 0x18);
        err += sn9c102_write_reg(cam, 0x50, 0x19);
 
-       err += sn9c102_i2c_write(cam, 0x12, 0x8d);
-       err += sn9c102_i2c_write(cam, 0x11, 0x00);
+       err += sn9c102_i2c_write(cam, 0x12, 0x80);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
        err += sn9c102_i2c_write(cam, 0x15, 0x34);
        err += sn9c102_i2c_write(cam, 0x16, 0x03);
        err += sn9c102_i2c_write(cam, 0x17, 0x1c);
@@ -43,12 +43,14 @@ static int ov7630_init(struct sn9c102_device* cam)
        err += sn9c102_i2c_write(cam, 0x19, 0x06);
        err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
        err += sn9c102_i2c_write(cam, 0x1b, 0x04);
-       err += sn9c102_i2c_write(cam, 0x20, 0x44);
+       err += sn9c102_i2c_write(cam, 0x20, 0xf6);
        err += sn9c102_i2c_write(cam, 0x23, 0xee);
        err += sn9c102_i2c_write(cam, 0x26, 0xa0);
        err += sn9c102_i2c_write(cam, 0x27, 0x9a);
-       err += sn9c102_i2c_write(cam, 0x28, 0x20);
+       err += sn9c102_i2c_write(cam, 0x28, 0xa0);
        err += sn9c102_i2c_write(cam, 0x29, 0x30);
+       err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
+       err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
        err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
        err += sn9c102_i2c_write(cam, 0x30, 0x24);
        err += sn9c102_i2c_write(cam, 0x32, 0x86);
@@ -80,7 +82,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
                err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
                break;
        case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
+               err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
                break;
        case V4L2_CID_GAIN:
                err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -108,7 +110,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
                err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
                break;
        case V4L2_CID_AUTO_WHITE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09);
+               err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
                break;
        case V4L2_CID_AUTOGAIN:
                err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
@@ -371,26 +373,29 @@ static struct sn9c102_sensor ov7630 = {
 
 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
 {
+       const struct usb_device_id ov7630_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x602c), },
+               { USB_DEVICE(0x0c45, 0x602d), },
+               { USB_DEVICE(0x0c45, 0x608f), },
+               { USB_DEVICE(0x0c45, 0x60b0), },
+               { }
+       };
        int err = 0;
 
-       sn9c102_attach_sensor(cam, &ov7630);
-
-       if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
-           le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
-           le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
-           le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
+       if (!sn9c102_match_id(cam, ov7630_id_table))
                return -ENODEV;
 
        err += sn9c102_write_reg(cam, 0x01, 0x01);
        err += sn9c102_write_reg(cam, 0x00, 0x01);
        err += sn9c102_write_reg(cam, 0x28, 0x17);
-
        if (err)
                return -EIO;
 
-       err += sn9c102_i2c_write(cam, 0x0b, 0);
+       err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
        if (err)
                return -ENODEV;
 
+       sn9c102_attach_sensor(cam, &ov7630);
+
        return 0;
 }
diff --git a/drivers/usb/media/sn9c102_pas202bca.c b/drivers/usb/media/sn9c102_pas202bca.c
new file mode 100644 (file)
index 0000000..3453237
--- /dev/null
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas202bca;
+
+
+static int pas202bca_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x30, 0x19);
+       err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+       err += sn9c102_i2c_write(cam, 0x02, 0x14);
+       err += sn9c102_i2c_write(cam, 0x03, 0x40);
+       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
+       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
+       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
+       err += sn9c102_i2c_write(cam, 0x10, 0x08);
+       err += sn9c102_i2c_write(cam, 0x13, 0x63);
+       err += sn9c102_i2c_write(cam, 0x15, 0x70);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       msleep(400);
+
+       return err;
+}
+
+
+static int pas202bca_set_pix_format(struct sn9c102_device* cam,
+                                    const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x24, 0x17);
+       else
+               err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+       return err;
+}
+
+
+static int pas202bca_set_ctrl(struct sn9c102_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static int pas202bca_set_crop(struct sn9c102_device* cam,
+                              const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &pas202bca;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor pas202bca = {
+       .name = "PAS202BCA",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x40,
+       .init = &pas202bca_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x0001,
+                       .default_value = 0x01e5,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x04,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &pas202bca_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &pas202bca_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &pas202bca_set_pix_format
+};
+
+
+int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
+{
+       const struct usb_device_id pas202bca_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x60af), },
+               { }
+       };
+       int err = 0;
+
+       if (!sn9c102_match_id(cam,pas202bca_id_table))
+               return -ENODEV;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x40, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &pas202bca);
+
+       return 0;
+}
index 5ca54c7..d068616 100644 (file)
@@ -263,7 +263,7 @@ static struct sn9c102_sensor pas202bcb = {
 
 
 int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
-{       
+{
        int r0 = 0, r1 = 0, err = 0;
        unsigned int pid = 0;
 
index 7d953b2..2afd9e9 100644 (file)
@@ -66,6 +66,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
 extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
 extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
@@ -81,12 +82,17 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {              \
        &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
        &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
        &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
+       &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
        &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
        &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
        &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
        NULL,                                                                 \
 };
 
+/* Device identification */
+extern struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
+
 /* Attach a probed sensor to the camera. */
 extern void 
 sn9c102_attach_sensor(struct sn9c102_device* cam,
@@ -108,6 +114,7 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
 static const struct usb_device_id sn9c102_id_table[] = {                      \
        { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
        { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
+       { USB_DEVICE(0x0c45, 0x6007), },                                      \
        { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
        { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
        { USB_DEVICE(0x0c45, 0x6024), },                                      \
@@ -126,7 +133,7 @@ static const struct usb_device_id sn9c102_id_table[] = {                      \
        { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
        { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
        { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */          \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */         \
        { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
        { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
        { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
@@ -359,12 +366,6 @@ struct sn9c102_sensor {
           error code without rolling back.
        */
 
-       const struct usb_device* usbdev;
-       /*
-          Points to the usb_device struct after the sensor is attached.
-          Do not touch unless you know what you are doing.
-       */
-
        /*
           Do NOT write to the data below, it's READ ONLY. It is used by the
           core module to store successfully updated values of the above
index 32ddf23..2e08c55 100644 (file)
@@ -142,14 +142,18 @@ static struct sn9c102_sensor tas5110c1b = {
 
 int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
 {
-       /* This sensor has no identifiers, so let's attach it anyway */
-       sn9c102_attach_sensor(cam, &tas5110c1b);
+       const struct usb_device_id tas5110c1b_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x6001), },
+               { USB_DEVICE(0x0c45, 0x6005), },
+               { USB_DEVICE(0x0c45, 0x60ab), },
+               { }
+       };
 
        /* Sensor detection is based on USB pid/vid */
-       if (le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6001 &&
-           le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6005 &&
-           le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x60ab)
+       if (!sn9c102_match_id(cam, tas5110c1b_id_table))
                return -ENODEV;
 
+       sn9c102_attach_sensor(cam, &tas5110c1b);
+
        return 0;
 }
index a0728f0..c7b3397 100644 (file)
@@ -153,13 +153,17 @@ static struct sn9c102_sensor tas5130d1b = {
 
 int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
 {
-       /* This sensor has no identifiers, so let's attach it anyway */
-       sn9c102_attach_sensor(cam, &tas5130d1b);
+       const struct usb_device_id tas5130d1b_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x6025), },
+               { USB_DEVICE(0x0c45, 0x60aa), },
+               { }
+       };
 
        /* Sensor detection is based on USB pid/vid */
-       if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6025 &&
-           le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x60aa)
+       if (!sn9c102_match_id(cam, tas5130d1b_id_table))
                return -ENODEV;
 
+       sn9c102_attach_sensor(cam, &tas5130d1b);
+
        return 0;
 }
index b497a6a..9636da2 100644 (file)
@@ -67,6 +67,7 @@
 #include <linux/errno.h>
 #include <linux/videodev.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #include "stv680.h"
 
@@ -317,12 +318,11 @@ static int stv_init (struct usb_stv *stv680)
        unsigned char *buffer;
        unsigned long int bufsize;
 
-       buffer = kmalloc (40, GFP_KERNEL);
+       buffer = kzalloc (40, GFP_KERNEL);
        if (buffer == NULL) {
                PDEBUG (0, "STV(e): Out of (small buf) memory");
                return -1;
        }
-       memset (buffer, 0, 40);
        udelay (100);
 
        /* set config 1, interface 0, alternate 0 */
@@ -1258,22 +1258,22 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
        unsigned long size  = vma->vm_end-vma->vm_start;
        unsigned long page, pos;
 
-       down (&stv680->lock);
+       mutex_lock(&stv680->lock);
 
        if (stv680->udev == NULL) {
-               up (&stv680->lock);
+               mutex_unlock(&stv680->lock);
                return -EIO;
        }
        if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
                    & ~(PAGE_SIZE - 1))) {
-               up (&stv680->lock);
+               mutex_unlock(&stv680->lock);
                return -EINVAL;
        }
        pos = (unsigned long) stv680->fbuf;
        while (size > 0) {
                page = vmalloc_to_pfn((void *)pos);
                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       up (&stv680->lock);
+                       mutex_unlock(&stv680->lock);
                        return -EAGAIN;
                }
                start += PAGE_SIZE;
@@ -1283,7 +1283,7 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
                else
                        size = 0;
        }
-       up (&stv680->lock);
+       mutex_unlock(&stv680->lock);
 
        return 0;
 }
@@ -1387,14 +1387,12 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
                goto error;
        }
        /* We found one */
-       if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
+       if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
                PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
                retval = -ENOMEM;
                goto error;
        }
 
-       memset (stv680, 0, sizeof (*stv680));
-
        stv680->udev = dev;
        stv680->camera_name = camera_name;
 
@@ -1409,7 +1407,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
 
        memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
        init_waitqueue_head (&stv680->wq);
-       init_MUTEX (&stv680->lock);
+       mutex_init (&stv680->lock);
        wmb ();
 
        if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
index b0551cd..ea46e00 100644 (file)
@@ -118,7 +118,7 @@ struct usb_stv {
        int origGain;
        int origMode;           /* original camera mode */
 
-       struct semaphore lock;  /* to lock the structure */
+       struct mutex lock;      /* to lock the structure */
        int user;               /* user count for exclusive use */
        int removed;            /* device disconnected */
        int streaming;          /* Are we streaming video? */
index 63a72e5..0b51fae 100644 (file)
@@ -690,14 +690,13 @@ int usbvideo_register(
        }
 
        base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
-       cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL);
+       cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
        if (cams == NULL) {
                err("Failed to allocate %d. bytes for usbvideo struct", base_size);
                return -ENOMEM;
        }
        dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
            __FUNCTION__, cams, base_size, num_cams);
-       memset(cams, 0, base_size);
 
        /* Copy callbacks, apply defaults for those that are not set */
        memmove(&cams->cb, cbTbl, sizeof(cams->cb));
@@ -715,7 +714,7 @@ int usbvideo_register(
        cams->md_module = md;
        if (cams->md_module == NULL)
                warn("%s: module == NULL!", __FUNCTION__);
-       init_MUTEX(&cams->lock);        /* to 1 == available */
+       mutex_init(&cams->lock);        /* to 1 == available */
 
        for (i = 0; i < num_cams; i++) {
                struct uvd *up = &cams->cam[i];
@@ -863,7 +862,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
        if (uvd->debug > 0)
                info("%s(%p.)", __FUNCTION__, intf);
 
-       down(&uvd->lock);
+       mutex_lock(&uvd->lock);
        uvd->remove_pending = 1; /* Now all ISO data will be ignored */
 
        /* At this time we ask to cancel outstanding URBs */
@@ -883,7 +882,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
                info("%s: In use, disconnect pending.", __FUNCTION__);
        else
                usbvideo_CameraRelease(uvd);
-       up(&uvd->lock);
+       mutex_unlock(&uvd->lock);
        info("USB camera disconnected.");
 
        usbvideo_ClientDecModCount(uvd);
@@ -930,19 +929,19 @@ static int usbvideo_find_struct(struct usbvideo *cams)
                err("No usbvideo handle?");
                return -1;
        }
-       down(&cams->lock);
+       mutex_lock(&cams->lock);
        for (u = 0; u < cams->num_cameras; u++) {
                struct uvd *uvd = &cams->cam[u];
                if (!uvd->uvd_used) /* This one is free */
                {
                        uvd->uvd_used = 1;      /* In use now */
-                       init_MUTEX(&uvd->lock); /* to 1 == available */
+                       mutex_init(&uvd->lock); /* to 1 == available */
                        uvd->dev = NULL;
                        rv = u;
                        break;
                }
        }
-       up(&cams->lock);
+       mutex_unlock(&cams->lock);
        return rv;
 }
 
@@ -984,7 +983,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
        /* Not relying upon caller we increase module counter ourselves */
        usbvideo_ClientIncModCount(uvd);
 
-       down(&uvd->lock);
+       mutex_lock(&uvd->lock);
        for (i=0; i < USBVIDEO_NUMSBUF; i++) {
                uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
                if (uvd->sbuf[i].urb == NULL) {
@@ -1007,7 +1006,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
         * return control to the client's probe function right now.
         */
 allocate_done:
-       up (&uvd->lock);
+       mutex_unlock(&uvd->lock);
        usbvideo_ClientDecModCount(uvd);
        return uvd;
 }
@@ -1121,7 +1120,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
                info("%s($%p)", __FUNCTION__, dev);
 
        usbvideo_ClientIncModCount(uvd);
-       down(&uvd->lock);
+       mutex_lock(&uvd->lock);
 
        if (uvd->user) {
                err("%s: Someone tried to open an already opened device!", __FUNCTION__);
@@ -1202,7 +1201,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
                        }
                }
        }
-       up(&uvd->lock);
+       mutex_unlock(&uvd->lock);
        if (errCode != 0)
                usbvideo_ClientDecModCount(uvd);
        if (uvd->debug > 0)
@@ -1231,7 +1230,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
        if (uvd->debug > 1)
                info("%s($%p)", __FUNCTION__, dev);
 
-       down(&uvd->lock);
+       mutex_lock(&uvd->lock);
        GET_CALLBACK(uvd, stopDataPump)(uvd);
        usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
        uvd->fbuf = NULL;
@@ -1252,7 +1251,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
                        info("usbvideo_v4l_close: Final disconnect.");
                usbvideo_CameraRelease(uvd);
        }
-       up(&uvd->lock);
+       mutex_unlock(&uvd->lock);
        usbvideo_ClientDecModCount(uvd);
 
        if (uvd->debug > 1)
@@ -1512,7 +1511,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
        if (uvd->debug >= 1)
                info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
 
-       down(&uvd->lock);       
+       mutex_lock(&uvd->lock);
 
        /* See if a frame is completed, then use it. */
        for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
@@ -1644,7 +1643,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
                }
        }
 read_done:
-       up(&uvd->lock); 
+       mutex_unlock(&uvd->lock);
        return count;
 }
 
index 6c390a1..135433c 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/config.h>
 #include <linux/videodev.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 /* Most helpful debugging aid */
 #define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
@@ -213,7 +214,7 @@ struct uvd {
        unsigned long flags;            /* FLAGS_USBVIDEO_xxx */
        unsigned long paletteBits;      /* Which palettes we accept? */
        unsigned short defaultPalette;  /* What palette to use for read() */
-       struct semaphore lock;
+       struct mutex lock;
        int user;               /* user count for exclusive use */
 
        videosize_t videosize;  /* Current setting */
@@ -272,7 +273,7 @@ struct usbvideo {
        int num_cameras;                /* As allocated */
        struct usb_driver usbdrv;       /* Interface to the USB stack */
        char drvName[80];               /* Driver name */
-       struct semaphore lock;          /* Mutex protecting camera structures */
+       struct mutex lock;              /* Mutex protecting camera structures */
        struct usbvideo_cb cb;          /* Table of callbacks (virtual methods) */
        struct video_device vdt;        /* Video device template */
        struct uvd *cam;                        /* Array of camera structures */
index 5df1440..1d06e53 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 #include "usbvideo.h"
 
 // #define VICAM_DEBUG
@@ -407,7 +408,7 @@ struct vicam_camera {
        struct usb_device *udev;        // usb device
 
        /* guard against simultaneous accesses to the camera */
-       struct semaphore cam_lock;
+       struct mutex cam_lock;
 
        int is_initialized;
        u8 open_count;
@@ -461,12 +462,12 @@ static int send_control_msg(struct vicam_camera *cam,
                            u16 size)
 {
        int status = -ENODEV;
-       down(&cam->cam_lock);
+       mutex_lock(&cam->cam_lock);
        if (cam->udev) {
                status = __send_control_msg(cam, request, value,
                                            index, cp, size);
        }
-       up(&cam->cam_lock);
+       mutex_unlock(&cam->cam_lock);
        return status;
 }
 static int
@@ -763,6 +764,7 @@ vicam_open(struct inode *inode, struct file *file)
        if (!cam) {
                printk(KERN_ERR
                       "vicam video_device improperly initialized");
+               return -EINVAL;
        }
 
        /* the videodev_lock held above us protects us from
@@ -831,13 +833,13 @@ vicam_close(struct inode *inode, struct file *file)
        rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
        kfree(cam->cntrlbuf);
 
-       down(&cam->cam_lock);
+       mutex_lock(&cam->cam_lock);
 
        cam->open_count--;
        open_count = cam->open_count;
        udev = cam->udev;
 
-       up(&cam->cam_lock);
+       mutex_unlock(&cam->cam_lock);
 
        if (!open_count && !udev) {
                kfree(cam);
@@ -960,7 +962,7 @@ read_frame(struct vicam_camera *cam, int framenum)
        request[8] = 0;
        // bytes 9-15 do not seem to affect exposure or image quality
 
-       down(&cam->cam_lock);
+       mutex_lock(&cam->cam_lock);
 
        if (!cam->udev) {
                goto done;
@@ -985,7 +987,7 @@ read_frame(struct vicam_camera *cam, int framenum)
        }
 
  done:
-       up(&cam->cam_lock);
+       mutex_unlock(&cam->cam_lock);
 }
 
 static ssize_t
@@ -1309,7 +1311,7 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
 
        cam->shutter_speed = 15;
 
-       init_MUTEX(&cam->cam_lock);
+       mutex_init(&cam->cam_lock);
 
        memcpy(&cam->vdev, &vicam_template,
               sizeof (vicam_template));
@@ -1351,7 +1353,7 @@ vicam_disconnect(struct usb_interface *intf)
 
        /* stop the camera from being used */
 
-       down(&cam->cam_lock);
+       mutex_lock(&cam->cam_lock);
 
        /* mark the camera as gone */
 
@@ -1368,7 +1370,7 @@ vicam_disconnect(struct usb_interface *intf)
 
        open_count = cam->open_count;
 
-       up(&cam->cam_lock);
+       mutex_unlock(&cam->cam_lock);
 
        if (!open_count) {
                kfree(cam);
index 9937fc6..b57dec3 100644 (file)
 #include "w9968cf.h"
 #include "w9968cf_decoder.h"
 
+static struct w9968cf_vpp_t* w9968cf_vpp;
+static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
+
+static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
+static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
+
+static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
 
 
 /****************************************************************************
@@ -695,13 +702,12 @@ static int w9968cf_allocate_memory(struct w9968cf_device* cam)
        /* Allocate memory for the isochronous transfer buffers */
        for (i = 0; i < W9968CF_URBS; i++) {
                if (!(cam->transfer_buffer[i] =
-                     kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
+                     kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
                        DBG(1, "Couldn't allocate memory for the isochronous "
                               "transfer buffers (%u bytes)", 
                            p_size * W9968CF_ISO_PACKETS)
                        return -ENOMEM;
                }
-               memset(cam->transfer_buffer[i], 0, W9968CF_ISO_PACKETS*p_size);
        }
 
        /* Allocate memory for the temporary frame buffer */
@@ -2419,7 +2425,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
                          enum w9968cf_model_id mod_id,
                          const unsigned short dev_nr)
 {
-       init_MUTEX(&cam->fileop_sem);
+       mutex_init(&cam->fileop_mutex);
        init_waitqueue_head(&cam->open);
        spin_lock_init(&cam->urb_lock);
        spin_lock_init(&cam->flist_lock);
@@ -2647,7 +2653,7 @@ static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
   --------------------------------------------------------------------------*/
 static void w9968cf_release_resources(struct w9968cf_device* cam)
 {
-       down(&w9968cf_devlist_sem);
+       mutex_lock(&w9968cf_devlist_mutex);
 
        DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
 
@@ -2658,7 +2664,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
        kfree(cam->control_buffer);
        kfree(cam->data_buffer);
 
-       up(&w9968cf_devlist_sem);
+       mutex_unlock(&w9968cf_devlist_mutex);
 }
 
 
@@ -2678,14 +2684,14 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
 
        cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
-       down(&cam->dev_sem);
+       mutex_lock(&cam->dev_mutex);
 
        if (cam->sensor == CC_UNKNOWN) {
                DBG(2, "No supported image sensor has been detected by the "
                       "'ovcamchip' module for the %s (/dev/video%d). Make "
                       "sure it is loaded *before* (re)connecting the camera.",
                    symbolic(camlist, cam->id), cam->v4ldev->minor)
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                up_read(&w9968cf_disconnect);
                return -ENODEV;
        }
@@ -2694,11 +2700,11 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
                DBG(2, "%s (/dev/video%d) has been already occupied by '%s'",
                    symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
                if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
-                       up(&cam->dev_sem);
+                       mutex_unlock(&cam->dev_mutex);
                        up_read(&w9968cf_disconnect);
                        return -EWOULDBLOCK;
                }
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                err = wait_event_interruptible_exclusive(cam->open,
                                                         cam->disconnected ||
                                                         !cam->users);
@@ -2710,7 +2716,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
                        up_read(&w9968cf_disconnect);
                        return -ENODEV;
                }
-               down(&cam->dev_sem);
+               mutex_lock(&cam->dev_mutex);
        }
 
        DBG(5, "Opening '%s', /dev/video%d ...",
@@ -2739,7 +2745,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
 
        DBG(5, "Video device is open")
 
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
        up_read(&w9968cf_disconnect);
 
        return 0;
@@ -2747,7 +2753,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
 deallocate_memory:
        w9968cf_deallocate_memory(cam);
        DBG(2, "Failed to open the video device")
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
        up_read(&w9968cf_disconnect);
        return err;
 }
@@ -2759,13 +2765,13 @@ static int w9968cf_release(struct inode* inode, struct file* filp)
 
        cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
-       down(&cam->dev_sem); /* prevent disconnect() to be called */
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
 
        w9968cf_stop_transfer(cam);
 
        if (cam->disconnected) {
                w9968cf_release_resources(cam);
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
                kfree(cam);
                return 0;
        }
@@ -2775,7 +2781,7 @@ static int w9968cf_release(struct inode* inode, struct file* filp)
        wake_up_interruptible_nr(&cam->open, 1);
 
        DBG(5, "Video device closed")
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
        return 0;
 }
 
@@ -2792,18 +2798,18 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
        if (filp->f_flags & O_NONBLOCK)
                return -EWOULDBLOCK;
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->disconnected) {
                DBG(2, "Device not present")
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->misconfigured) {
                DBG(2, "The camera is misconfigured. Close and open it again.")
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
@@ -2818,11 +2824,11 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
                                       cam->frame[1].status == F_READY ||
                                       cam->disconnected);
        if (err) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return err;
        }
        if (cam->disconnected) {
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
@@ -2836,7 +2842,7 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 
        if (copy_to_user(buf, fr->buffer, count)) {
                fr->status = F_UNUSED;
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EFAULT;
        }
        *f_pos += count;
@@ -2845,7 +2851,7 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 
        DBG(5, "%zu bytes read", count)
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
        return count;
 }
 
@@ -2899,24 +2905,24 @@ w9968cf_ioctl(struct inode* inode, struct file* filp,
 
        cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
-       if (down_interruptible(&cam->fileop_sem))
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
                return -ERESTARTSYS;
 
        if (cam->disconnected) {
                DBG(2, "Device not present")
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -ENODEV;
        }
 
        if (cam->misconfigured) {
                DBG(2, "The camera is misconfigured. Close and open it again.")
-               up(&cam->fileop_sem);
+               mutex_unlock(&cam->fileop_mutex);
                return -EIO;
        }
 
        err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg);
 
-       up(&cam->fileop_sem);
+       mutex_unlock(&cam->fileop_mutex);
        return err;
 }
 
@@ -3499,14 +3505,12 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                return -ENODEV;
 
        cam = (struct w9968cf_device*)
-                 kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
+                 kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
        if (!cam)
                return -ENOMEM;
 
-       memset(cam, 0, sizeof(*cam));
-
-       init_MUTEX(&cam->dev_sem);
-       down(&cam->dev_sem);
+       mutex_init(&cam->dev_mutex);
+       mutex_lock(&cam->dev_mutex);
 
        cam->usbdev = udev;
        /* NOTE: a local copy is used to avoid possible race conditions */
@@ -3518,10 +3522,10 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
                simcams = W9968CF_SIMCAMS;
 
        /* How many cameras are connected ? */
-       down(&w9968cf_devlist_sem);
+       mutex_lock(&w9968cf_devlist_mutex);
        list_for_each(ptr, &w9968cf_dev_list)
                sc++;
-       up(&w9968cf_devlist_sem);
+       mutex_unlock(&w9968cf_devlist_mutex);
 
        if (sc >= simcams) {
                DBG(2, "Device rejected: too many connected cameras "
@@ -3532,21 +3536,19 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
 
        /* Allocate 2 bytes of memory for camera control USB transfers */
-       if (!(cam->control_buffer = kmalloc(2, GFP_KERNEL))) {
+       if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
                DBG(1,"Couldn't allocate memory for camera control transfers")
                err = -ENOMEM;
                goto fail;
        }
-       memset(cam->control_buffer, 0, 2);
 
        /* Allocate 8 bytes of memory for USB data transfers to the FSB */
-       if (!(cam->data_buffer = kmalloc(8, GFP_KERNEL))) {
+       if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
                DBG(1, "Couldn't allocate memory for data "
                       "transfers to the FSB")
                err = -ENOMEM;
                goto fail;
        }
-       memset(cam->data_buffer, 0, 8);
 
        /* Register the V4L device */
        cam->v4ldev = video_device_alloc();
@@ -3583,9 +3585,9 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
 
        /* Add a new entry into the list of V4L registered devices */
-       down(&w9968cf_devlist_sem);
+       mutex_lock(&w9968cf_devlist_mutex);
        list_add(&cam->v4llist, &w9968cf_dev_list);
-       up(&w9968cf_devlist_sem);
+       mutex_unlock(&w9968cf_devlist_mutex);
        dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
        w9968cf_turn_on_led(cam);
@@ -3593,7 +3595,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        w9968cf_i2c_init(cam);
 
        usb_set_intfdata(intf, cam);
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
        return 0;
 
 fail: /* Free unused memory */
@@ -3601,7 +3603,7 @@ fail: /* Free unused memory */
        kfree(cam->data_buffer);
        if (cam->v4ldev)
                video_device_release(cam->v4ldev);
-       up(&cam->dev_sem);
+       mutex_unlock(&cam->dev_mutex);
        kfree(cam);
        return err;
 }
@@ -3616,7 +3618,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
 
        if (cam) {
                /* Prevent concurrent accesses to data */
-               down(&cam->dev_sem); 
+               mutex_lock(&cam->dev_mutex);
 
                cam->disconnected = 1;
 
@@ -3635,7 +3637,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
                } else
                        w9968cf_release_resources(cam);
 
-               up(&cam->dev_sem);
+               mutex_unlock(&cam->dev_mutex);
 
                if (!cam->users)
                        kfree(cam);
index 47a6ff7..a87be71 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/param.h>
 #include <linux/types.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <media/ovcamchip.h>
 
@@ -194,14 +194,6 @@ enum w9968cf_vpp_flag {
        VPP_UYVY_TO_RGBX = 0x08,
 };
 
-static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
-
-static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
-static DECLARE_MUTEX(w9968cf_devlist_sem); /* semaphore for list traversal */
-
-static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
-
 /* Main device driver structure */
 struct w9968cf_device {
        struct device dev; /* device structure */
@@ -277,8 +269,8 @@ struct w9968cf_device {
        struct i2c_client* sensor_client;
 
        /* Locks */
-       struct semaphore dev_sem,    /* for probe, disconnect,open and close */
-                        fileop_sem; /* for read and ioctl */
+       struct mutex dev_mutex,    /* for probe, disconnect,open and close */
+                        fileop_mutex; /* for read and ioctl */
        spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
                   flist_lock; /* for requested frame list accesses */
        wait_queue_head_t open, wait_queue;
diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h
new file mode 100644 (file)
index 0000000..8e06551
--- /dev/null
@@ -0,0 +1,192 @@
+/***************************************************************************
+ * V4L2 driver for ZC0301 Image Processor and Control Chip                 *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ZC0301_H_
+#define _ZC0301_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+
+#include "zc0301_sensor.h"
+
+/*****************************************************************************/
+
+#define ZC0301_DEBUG
+#define ZC0301_DEBUG_LEVEL         2
+#define ZC0301_MAX_DEVICES         64
+#define ZC0301_FORCE_MUNMAP        0
+#define ZC0301_MAX_FRAMES          32
+#define ZC0301_COMPRESSION_QUALITY 0
+#define ZC0301_URBS                2
+#define ZC0301_ISO_PACKETS         7
+#define ZC0301_ALTERNATE_SETTING   7
+#define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
+#define ZC0301_CTRL_TIMEOUT        100
+#define ZC0301_FRAME_TIMEOUT       2
+
+/*****************************************************************************/
+
+ZC0301_ID_TABLE
+ZC0301_SENSOR_TABLE
+
+enum zc0301_frame_state {
+       F_UNUSED,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+struct zc0301_frame_t {
+       void* bufmem;
+       struct v4l2_buffer buf;
+       enum zc0301_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+};
+
+enum zc0301_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+enum zc0301_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum zc0301_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+struct zc0301_module_param {
+       u8 force_munmap;
+       u16 frame_timeout;
+};
+
+static DECLARE_RWSEM(zc0301_disconnect);
+
+struct zc0301_device {
+       struct video_device* v4ldev;
+
+       struct zc0301_sensor sensor;
+
+       struct usb_device* usbdev;
+       struct urb* urb[ZC0301_URBS];
+       void* transfer_buffer[ZC0301_URBS];
+       u8* control_buffer;
+
+       struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
+       struct list_head inqueue, outqueue;
+       u32 frame_count, nbuffers, nreadbuffers;
+
+       enum zc0301_io_method io;
+       enum zc0301_stream_state stream;
+
+       struct v4l2_jpegcompression compression;
+
+       struct zc0301_module_param module_param;
+
+       enum zc0301_dev_state state;
+       u8 users;
+
+       struct mutex dev_mutex, fileop_mutex;
+       spinlock_t queue_lock;
+       wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
+{
+       return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
+}
+
+void
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
+{
+       memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef ZC0301_DEBUG
+#      define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+               else if ((level) == 2)                                        \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+               else if ((level) >= 3)                                        \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+} while (0)
+#      define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1 || (level) == 2)                             \
+                       pr_info("zc0301: " fmt "\n", ## args);                \
+               else if ((level) == 3)                                        \
+                       pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#else
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _ZC0301_H_ */
diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c
new file mode 100644 (file)
index 0000000..4036c62
--- /dev/null
@@ -0,0 +1,2055 @@
+/***************************************************************************
+ * Video4Linux2 driver for ZC0301 Image Processor and Control Chip         *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Informations about the chip internals needed to enable the I2C protocol *
+ * have been taken from the documentation of the ZC030x Video4Linux1       *
+ * driver written by Andrew Birkett <andy@nobugs.org>                      *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "zc0301.h"
+
+/*****************************************************************************/
+
+#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301 "                       \
+                              "Image Processor and Control Chip"
+#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
+#define ZC0301_MODULE_LICENSE "GPL"
+#define ZC0301_MODULE_VERSION "1:1.03"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 3)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, zc0301_id_table);
+
+MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
+MODULE_VERSION(ZC0301_MODULE_VERSION);
+MODULE_LICENSE(ZC0301_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                 "\n -1 = use next available (default)"
+                 "\n  n = use minor number n (integer >= 0)"
+                 "\nYou can specify up to "
+                 __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
+                 "\nFor example:"
+                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                 "\nthe second registered camera and use auto for the first"
+                 "\none and for every other camera."
+                 "\n");
+
+static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                               ZC0301_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                 "\n<0|1[,...]> Force the application to unmap previously"
+                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                 "\nthis feature. This parameter is specific for each"
+                 "\ndetected camera."
+                 "\n 0 = do not force memory unmapping"
+                 "\n 1 = force memory unmapping (save memory)"
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                 "\n");
+
+static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                                       ZC0301_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
+                 "\n");
+
+#ifdef ZC0301_DEBUG
+static unsigned short debug = ZC0301_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                 "\n<n> Debugging information level, from 0 to 3:"
+                 "\n0 = none (use carefully)"
+                 "\n1 = critical errors"
+                 "\n2 = significant informations"
+                 "\n3 = more verbose messages"
+                 "\nLevel 3 is useful for testing only, when only "
+                 "one device is used."
+                 "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
+                 "\n");
+#endif
+
+/*****************************************************************************/
+
+static u32
+zc0301_request_buffers(struct zc0301_device* cam, u32 count,
+                       enum zc0301_io_method io)
+{
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+       const size_t imagesize = cam->module_param.force_munmap ||
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
+       void* buff = NULL;
+       u32 i;
+
+       if (count > ZC0301_MAX_FRAMES)
+               count = ZC0301_MAX_FRAMES;
+
+       cam->nbuffers = count;
+       while (cam->nbuffers > 0) {
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+                       break;
+               cam->nbuffers--;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.index = i;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.length = imagesize;
+               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buf.sequence = 0;
+               cam->frame[i].buf.field = V4L2_FIELD_NONE;
+               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buf.flags = 0;
+       }
+
+       return cam->nbuffers;
+}
+
+
+static void zc0301_release_buffers(struct zc0301_device* cam)
+{
+       if (cam->nbuffers) {
+               vfree(cam->frame[0].bufmem);
+               cam->nbuffers = 0;
+       }
+       cam->frame_current = NULL;
+}
+
+
+static void zc0301_empty_framequeues(struct zc0301_device* cam)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&cam->inqueue);
+       INIT_LIST_HEAD(&cam->outqueue);
+
+       for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
+               cam->frame[i].state = F_UNUSED;
+               cam->frame[i].buf.bytesused = 0;
+       }
+}
+
+
+static void zc0301_requeue_outqueue(struct zc0301_device* cam)
+{
+       struct zc0301_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void zc0301_queue_unusedframes(struct zc0301_device* cam)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].state == F_UNUSED) {
+                       cam->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               }
+}
+
+/*****************************************************************************/
+
+int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
+{
+       struct usb_device* udev = cam->usbdev;
+       int res;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
+                             value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
+       if (res < 0) {
+               DBG(3, "Failed to write a register (index 0x%04X, "
+                      "value 0x%02X, error %d)",index, value, res);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int zc0301_read_reg(struct zc0301_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
+                             0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
+       if (res < 0)
+               DBG(3, "Failed to read a register (index 0x%04X, error %d)",
+                   index, res);
+
+       PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
+{
+       int err = 0, res, r0, r1;
+
+       err += zc0301_write_reg(cam, 0x0092, address);
+       err += zc0301_write_reg(cam, 0x0090, 0x02);
+
+       msleep(1);
+
+       res = zc0301_read_reg(cam, 0x0091);
+       if (res < 0)
+               err += res;
+       r0 = zc0301_read_reg(cam, 0x0095);
+       if (r0 < 0)
+               err += r0;
+       r1 = zc0301_read_reg(cam, 0x0096);
+       if (r1 < 0)
+               err += r1;
+
+       res = (length <= 1) ? r0 : r0 | (r1 << 8);
+
+       if (err)
+               DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
+                   address, res);
+
+
+       PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
+
+       return err ? -1 : res;
+}
+
+
+int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
+{
+       int err = 0, res;
+
+       err += zc0301_write_reg(cam, 0x0092, address);
+       err += zc0301_write_reg(cam, 0x0093, value & 0xff);
+       err += zc0301_write_reg(cam, 0x0094, value >> 8);
+       err += zc0301_write_reg(cam, 0x0090, 0x01);
+
+       msleep(1);
+
+       res = zc0301_read_reg(cam, 0x0091);
+       if (res < 0)
+               err += res;
+
+       if (err)
+               DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
+                   address, value);
+
+       PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
+
+       return err ? -1 : 0;
+}
+
+/*****************************************************************************/
+
+static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+       struct zc0301_device* cam = urb->context;
+       struct zc0301_frame_t** f;
+       size_t imagesize;
+       u8 i;
+       int err = 0;
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &cam->frame_current;
+
+       if (cam->stream == STREAM_INTERRUPT) {
+               cam->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               DBG(3, "Stream interrupted");
+               wake_up(&cam->wait_stream);
+       }
+
+       if (cam->state & DEV_DISCONNECTED)
+               return;
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               wake_up_interruptible(&cam->wait_frame);
+               return;
+       }
+
+       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+               goto resubmit_urb;
+
+       if (!(*f))
+               (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
+                                 frame);
+
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int len, status;
+               void *pos;
+               u16* soi;
+               u8 sof;
+
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status) {
+                       DBG(3, "Error in isochronous frame");
+                       (*f)->state = F_ERROR;
+                       continue;
+               }
+
+               sof = (*(soi = pos) == 0xd8ff);
+
+               PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
+
+               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
+start_of_frame:
+                       if (sof) {
+                               (*f)->state = F_GRABBING;
+                               (*f)->buf.bytesused = 0;
+                               do_gettimeofday(&(*f)->buf.timestamp);
+                               DBG(3, "SOF detected: new video frame");
+                       }
+
+               if ((*f)->state == F_GRABBING) {
+                       if (sof && (*f)->buf.bytesused)
+                                       goto end_of_frame;
+
+                       if ((*f)->buf.bytesused + len > imagesize) {
+                               DBG(3, "Video frame size exceeded");
+                               (*f)->state = F_ERROR;
+                               continue;
+                       }
+
+                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
+                       (*f)->buf.bytesused += len;
+
+                       if ((*f)->buf.bytesused == imagesize) {
+                               u32 b;
+end_of_frame:
+                               b = (*f)->buf.bytesused;
+                               (*f)->state = F_DONE;
+                               (*f)->buf.sequence= ++cam->frame_count;
+                               spin_lock(&cam->queue_lock);
+                               list_move_tail(&(*f)->frame, &cam->outqueue);
+                               if (!list_empty(&cam->inqueue))
+                                       (*f) = list_entry(cam->inqueue.next,
+                                                      struct zc0301_frame_t,
+                                                         frame);
+                               else
+                                       (*f) = NULL;
+                               spin_unlock(&cam->queue_lock);
+                               DBG(3, "Video frame captured: : %lu bytes",
+                                      (unsigned long)(b));
+
+                               if (!(*f))
+                                       goto resubmit_urb;
+
+                               if (sof)
+                                       goto start_of_frame;
+                       }
+               }
+       }
+
+resubmit_urb:
+       urb->dev = cam->usbdev;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0 && err != -EPERM) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "usb_submit_urb() failed");
+       }
+
+       wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int zc0301_start_transfer(struct zc0301_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
+                                              512, 768, 1023};
+       const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
+       s8 i, j;
+       int err = 0;
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
+                                                 GFP_KERNEL);
+               if (!cam->transfer_buffer[i]) {
+                       err = -ENOMEM;
+                       DBG(1, "Not enough memory");
+                       goto free_buffers;
+               }
+       }
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       err = -ENOMEM;
+                       DBG(1, "usb_alloc_urb() failed");
+                       goto free_urbs;
+               }
+               urb->dev = udev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = ZC0301_ISO_PACKETS;
+               urb->complete = zc0301_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = psz * j;
+                       urb->iso_frame_desc[j].length = psz;
+               }
+       }
+
+       err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
+       if (err) {
+               DBG(1, "usb_set_interface() failed");
+               goto free_urbs;
+       }
+
+       cam->frame_current = NULL;
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       for (j = i-1; j >= 0; j--)
+                               usb_kill_urb(cam->urb[j]);
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
+                       goto free_urbs;
+               }
+       }
+
+       return 0;
+
+free_urbs:
+       for (i = 0; (i < ZC0301_URBS) &&  cam->urb[i]; i++)
+               usb_free_urb(cam->urb[i]);
+
+free_buffers:
+       for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
+               kfree(cam->transfer_buffer[i]);
+
+       return err;
+}
+
+
+static int zc0301_stop_transfer(struct zc0301_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       s8 i;
+       int err = 0;
+
+       if (cam->state & DEV_DISCONNECTED)
+               return 0;
+
+       for (i = ZC0301_URBS-1; i >= 0; i--) {
+               usb_kill_urb(cam->urb[i]);
+               usb_free_urb(cam->urb[i]);
+               kfree(cam->transfer_buffer[i]);
+       }
+
+       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       if (err)
+               DBG(3, "usb_set_interface() failed");
+
+       return err;
+}
+
+
+static int zc0301_stream_interrupt(struct zc0301_device* cam)
+{
+       long timeout;
+
+       cam->stream = STREAM_INTERRUPT;
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    ZC0301_URB_TIMEOUT);
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (cam->stream != STREAM_OFF) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "URB timeout reached. The camera is misconfigured. To "
+                      "use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+zc0301_set_compression(struct zc0301_device* cam,
+                       struct v4l2_jpegcompression* compression)
+{
+       int r, err = 0;
+
+       if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
+               err += r;
+       err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
+
+       return err ? -EIO : 0;
+}
+
+
+static int zc0301_init(struct zc0301_device* cam)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       struct v4l2_queryctrl *qctrl;
+       struct v4l2_rect* rect;
+       u8 i = 0;
+       int err = 0;
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_waitqueue_head(&cam->open);
+               qctrl = s->qctrl;
+               rect = &(s->cropcap.defrect);
+               cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
+       } else { /* use current values */
+               qctrl = s->_qctrl;
+               rect = &(s->_rect);
+       }
+
+       if (s->init) {
+               err = s->init(cam);
+               if (err) {
+                       DBG(3, "Sensor initialization failed");
+                       return err;
+               }
+       }
+
+       if ((err = zc0301_set_compression(cam, &cam->compression))) {
+               DBG(3, "set_compression() failed");
+               return err;
+       }
+
+       if (s->set_crop)
+               if ((err = s->set_crop(cam, rect))) {
+                       DBG(3, "set_crop() failed");
+                       return err;
+               }
+
+       if (s->set_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (s->qctrl[i].id != 0 &&
+                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+                               ctrl.id = s->qctrl[i].id;
+                               ctrl.value = qctrl[i].default_value;
+                               err = s->set_ctrl(cam, &ctrl);
+                               if (err) {
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name);
+                                       return err;
+                               }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name);
+                       }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               mutex_init(&cam->fileop_mutex);
+               spin_lock_init(&cam->queue_lock);
+               init_waitqueue_head(&cam->wait_frame);
+               init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
+               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+               memcpy(&(s->_rect), &(s->cropcap.defrect),
+                      sizeof(struct v4l2_rect));
+               cam->state |= DEV_INITIALIZED;
+       }
+
+       DBG(2, "Initialization succeeded");
+       return 0;
+}
+
+
+static void zc0301_release_resources(struct zc0301_device* cam)
+{
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+       video_set_drvdata(cam->v4ldev, NULL);
+       video_unregister_device(cam->v4ldev);
+       kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int zc0301_open(struct inode* inode, struct file* filp)
+{
+       struct zc0301_device* cam;
+       int err = 0;
+
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
+       if (!down_read_trylock(&zc0301_disconnect))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
+               up_read(&zc0301_disconnect);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               if ((filp->f_flags & O_NONBLOCK) ||
+                   (filp->f_flags & O_NDELAY)) {
+                       err = -EWOULDBLOCK;
+                       goto out;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
+               if (err) {
+                       up_read(&zc0301_disconnect);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up_read(&zc0301_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               err = zc0301_init(cam);
+               if (err) {
+                       DBG(1, "Initialization failed again. "
+                              "I will retry on next open().");
+                       goto out;
+               }
+               cam->state &= ~DEV_MISCONFIGURED;
+       }
+
+       if ((err = zc0301_start_transfer(cam)))
+               goto out;
+
+       filp->private_data = cam;
+       cam->users++;
+       cam->io = IO_NONE;
+       cam->stream = STREAM_OFF;
+       cam->nbuffers = 0;
+       cam->frame_count = 0;
+       zc0301_empty_framequeues(cam);
+
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&zc0301_disconnect);
+       return err;
+}
+
+
+static int zc0301_release(struct inode* inode, struct file* filp)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       zc0301_stop_transfer(cam);
+
+       zc0301_release_buffers(cam);
+
+       if (cam->state & DEV_DISCONNECTED) {
+               zc0301_release_resources(cam);
+               usb_put_dev(cam->usbdev);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+}
+
+
+static ssize_t
+zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_frame_t* f, * i;
+       unsigned long lock_flags;
+       long timeout;
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io == IO_MMAP) {
+               DBG(3, "Close and open the device again to choose the read "
+                      "method");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
+                       DBG(1, "read() failed, not enough memory");
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENOMEM;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       zc0301_empty_framequeues(cam);
+               zc0301_queue_unusedframes(cam);
+       }
+
+       if (!count) {
+               mutex_unlock(&cam->fileop_mutex);
+               return 0;
+       }
+
+       if (list_empty(&cam->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENODEV;
+               }
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EIO;
+               }
+       }
+
+       f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
+
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_for_each_entry(i, &cam->outqueue, frame)
+               i->state = F_UNUSED;
+       INIT_LIST_HEAD(&cam->outqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       zc0301_queue_unusedframes(cam);
+
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err ? err : count;
+}
+
+
+static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_frame_t* f;
+       unsigned long lock_flags;
+       unsigned int mask = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return POLLERR;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               goto error;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               goto error;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
+                       DBG(1, "poll() failed, not enough memory");
+                       goto error;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               zc0301_queue_unusedframes(cam);
+       }
+
+       poll_wait(filp, &cam->wait_frame, wait);
+
+       if (!list_empty(&cam->outqueue))
+               mask |= POLLIN | POLLRDNORM;
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return mask;
+
+error:
+       mutex_unlock(&cam->fileop_mutex);
+       return POLLERR;
+}
+
+
+static void zc0301_vm_open(struct vm_area_struct* vma)
+{
+       struct zc0301_frame_t* f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+
+static void zc0301_vm_close(struct vm_area_struct* vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct zc0301_frame_t* f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct zc0301_vm_ops = {
+       .open = zc0301_vm_open,
+       .close = zc0301_vm_close,
+};
+
+
+static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       unsigned long size = vma->vm_end - vma->vm_start,
+                     start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == cam->nbuffers) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;
+
+       pos = cam->frame[i].bufmem;
+       while (size > 0) { /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &zc0301_vm_ops;
+       vma->vm_private_data = &cam->frame[i];
+
+       zc0301_vm_open(vma);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_capability cap = {
+               .driver = "zc0301",
+               .version = ZC0301_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
+
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
+
+       if (i.index)
+               return -EINVAL;
+
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
+{
+       int index;
+
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
+
+       if (index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
+
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
+static int
+zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
+
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       if (!s->get_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
+                       }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
+
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
+
+       return err;
+}
+
+
+static int
+zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
+
+       if (!s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
+
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
+
+       s->_qctrl[i].default_value = ctrl.value;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
+
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
+
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       const enum zc0301_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
+
+       rect = &(crop.c);
+
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (!s->set_crop) {
+               memcpy(rect, &(s->_rect), sizeof(*rect));
+               if (copy_to_user(arg, &crop, sizeof(crop)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       rect->left &= ~7L;
+       rect->top &= ~7L;
+       if (rect->width < 8)
+               rect->width = 8;
+       if (rect->height < 8)
+               rect->height = 8;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+       rect->width &= ~7L;
+       rect->height &= ~7L;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               zc0301_release_buffers(cam);
+
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       s->pix_format.width = rect->width;
+       s->pix_format.height = rect->height;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               zc0301_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               zc0301_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
+
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
+
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "JPEG");
+               fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
+
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       pfmt->bytesperline = 0;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
+                        void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       const enum zc0301_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       pix = &(format.fmt.pix);
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memcpy(&rect, &(s->_rect), sizeof(rect));
+
+       if (!s->set_crop) {
+               pix->width = rect.width;
+               pix->height = rect.height;
+       } else {
+               rect.width = pix->width;
+               rect.height = pix->height;
+       }
+
+       if (rect.width < 8)
+               rect.width = 8;
+       if (rect.height < 8)
+               rect.height = 8;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
+       rect.width &= ~7L;
+       rect.height &= ~7L;
+
+       pix->width = rect.width;
+       pix->height = rect.height;
+       pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv;
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = 0;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_FMT failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               zc0301_release_buffers(cam);
+
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               zc0301_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               zc0301_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum zc0301_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       err += zc0301_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       cam->compression.quality = jc.quality;
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. "
+                              "Previous buffers are still mapped.");
+                       return -EINVAL;
+               }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       zc0301_empty_framequeues(cam);
+
+       zc0301_release_buffers(cam);
+       if (rb.count)
+               rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
+
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               zc0301_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
+       }
+
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
+
+       cam->frame[b.index].state = F_QUEUED;
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
+                    void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct zc0301_frame_t *f;
+       unsigned long lock_flags;
+       long timeout;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
+                       return -EIO;
+       }
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       zc0301_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
+               sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+       return 0;
+}
+
+
+static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
+                             unsigned int cmd, void __user * arg)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOC_QUERYCAP:
+               return zc0301_vidioc_querycap(cam, arg);
+
+       case VIDIOC_ENUMINPUT:
+               return zc0301_vidioc_enuminput(cam, arg);
+
+       case VIDIOC_G_INPUT:
+               return zc0301_vidioc_g_input(cam, arg);
+
+       case VIDIOC_S_INPUT:
+               return zc0301_vidioc_s_input(cam, arg);
+
+       case VIDIOC_QUERYCTRL:
+               return zc0301_vidioc_query_ctrl(cam, arg);
+
+       case VIDIOC_G_CTRL:
+               return zc0301_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return zc0301_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return zc0301_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return zc0301_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return zc0301_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return zc0301_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return zc0301_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return zc0301_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return zc0301_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return zc0301_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return zc0301_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return zc0301_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return zc0301_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return zc0301_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return zc0301_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return zc0301_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return zc0301_vidioc_s_parm(cam, arg);
+
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYMENU:
+               return -EINVAL;
+
+       default:
+               return -EINVAL;
+
+       }
+}
+
+
+static int zc0301_ioctl(struct inode* inode, struct file* filp,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       V4LDBG(3, "zc0301", cmd);
+
+       err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err;
+}
+
+
+static struct file_operations zc0301_fops = {
+       .owner =   THIS_MODULE,
+       .open =    zc0301_open,
+       .release = zc0301_release,
+       .ioctl =   zc0301_ioctl,
+       .read =    zc0301_read,
+       .poll =    zc0301_poll,
+       .mmap =    zc0301_mmap,
+       .llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+static int
+zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct zc0301_device* cam;
+       static unsigned int dev_nr = 0;
+       unsigned int i;
+       int err = 0;
+
+       if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
+               return -ENOMEM;
+
+       cam->usbdev = udev;
+
+       if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!(cam->v4ldev = video_device_alloc())) {
+               DBG(1, "video_device_alloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       mutex_init(&cam->dev_mutex);
+
+       DBG(2, "ZC0301 Image Processor and Control Chip detected "
+              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+
+       for  (i = 0; zc0301_sensor_table[i]; i++) {
+               err = zc0301_sensor_table[i](cam);
+               if (!err)
+                       break;
+       }
+
+       if (!err)
+               DBG(2, "%s image sensor detected", cam->sensor.name);
+       else {
+               DBG(1, "No supported image sensor detected");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (zc0301_init(cam)) {
+               DBG(1, "Initialization failed. I will retry on open().");
+               cam->state |= DEV_MISCONFIGURED;
+       }
+
+       strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = 0;
+       cam->v4ldev->fops = &zc0301_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+
+       mutex_lock(&cam->dev_mutex);
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L2 device registration failed");
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(1, "Free /dev/videoX node not found");
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               mutex_unlock(&cam->dev_mutex);
+               goto fail;
+       }
+
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+       cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
+
+       dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+       usb_set_intfdata(intf, cam);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+
+fail:
+       if (cam) {
+               kfree(cam->control_buffer);
+               if (cam->v4ldev)
+                       video_device_release(cam->v4ldev);
+               kfree(cam);
+       }
+       return err;
+}
+
+
+static void zc0301_usb_disconnect(struct usb_interface* intf)
+{
+       struct zc0301_device* cam = usb_get_intfdata(intf);
+
+       if (!cam)
+               return;
+
+       down_write(&zc0301_disconnect);
+
+       mutex_lock(&cam->dev_mutex);
+
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+       wake_up_interruptible_all(&cam->open);
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is open! Deregistration and "
+                      "memory deallocation are deferred on close.",
+                   cam->v4ldev->minor);
+               cam->state |= DEV_MISCONFIGURED;
+               zc0301_stop_transfer(cam);
+               cam->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&cam->wait_frame);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
+       } else {
+               cam->state |= DEV_DISCONNECTED;
+               zc0301_release_resources(cam);
+       }
+
+       mutex_unlock(&cam->dev_mutex);
+
+       if (!cam->users)
+               kfree(cam);
+
+       up_write(&zc0301_disconnect);
+}
+
+
+static struct usb_driver zc0301_usb_driver = {
+       .name =       "zc0301",
+       .id_table =   zc0301_id_table,
+       .probe =      zc0301_usb_probe,
+       .disconnect = zc0301_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init zc0301_module_init(void)
+{
+       int err = 0;
+
+       KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
+       KDBG(3, ZC0301_MODULE_AUTHOR);
+
+       if ((err = usb_register(&zc0301_usb_driver)))
+               KDBG(1, "usb_register() failed");
+
+       return err;
+}
+
+
+static void __exit zc0301_module_exit(void)
+{
+       usb_deregister(&zc0301_usb_driver);
+}
+
+
+module_init(zc0301_module_init);
+module_exit(zc0301_module_exit);
diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c
new file mode 100644 (file)
index 0000000..9d282a2
--- /dev/null
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * Plug-in for PAS202BCB image sensor connected to the ZC030! Image        *
+ * Processor and Control Chip                                              *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Initialization values of the ZC0301 have been taken from the SPCA5XX    *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+/*
+   NOTE: Sensor controls are disabled for now, becouse changing them while
+         streaming sometimes results in out-of-sync video frames. We'll use
+         the default initialization, until we know how to stop and start video
+         in the chip. However, the image quality still looks good under various
+         light conditions.
+*/
+
+#include <linux/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pas202bcb;
+
+
+static int pas202bcb_init(struct zc0301_device* cam)
+{
+       int err = 0;
+
+       err += zc0301_write_reg(cam, 0x0002, 0x00);
+       err += zc0301_write_reg(cam, 0x0003, 0x02);
+       err += zc0301_write_reg(cam, 0x0004, 0x80);
+       err += zc0301_write_reg(cam, 0x0005, 0x01);
+       err += zc0301_write_reg(cam, 0x0006, 0xE0);
+       err += zc0301_write_reg(cam, 0x0098, 0x00);
+       err += zc0301_write_reg(cam, 0x009A, 0x03);
+       err += zc0301_write_reg(cam, 0x011A, 0x00);
+       err += zc0301_write_reg(cam, 0x011C, 0x03);
+       err += zc0301_write_reg(cam, 0x009B, 0x01);
+       err += zc0301_write_reg(cam, 0x009C, 0xE6);
+       err += zc0301_write_reg(cam, 0x009D, 0x02);
+       err += zc0301_write_reg(cam, 0x009E, 0x86);
+
+       err += zc0301_i2c_write(cam, 0x02, 0x02);
+       err += zc0301_i2c_write(cam, 0x0A, 0x01);
+       err += zc0301_i2c_write(cam, 0x0B, 0x01);
+       err += zc0301_i2c_write(cam, 0x0D, 0x00);
+       err += zc0301_i2c_write(cam, 0x12, 0x05);
+       err += zc0301_i2c_write(cam, 0x13, 0x63);
+       err += zc0301_i2c_write(cam, 0x15, 0x70);
+
+       err += zc0301_write_reg(cam, 0x0101, 0xB7);
+       err += zc0301_write_reg(cam, 0x0100, 0x0D);
+       err += zc0301_write_reg(cam, 0x0189, 0x06);
+       err += zc0301_write_reg(cam, 0x01AD, 0x00);
+       err += zc0301_write_reg(cam, 0x01C5, 0x03);
+       err += zc0301_write_reg(cam, 0x01CB, 0x13);
+       err += zc0301_write_reg(cam, 0x0250, 0x08);
+       err += zc0301_write_reg(cam, 0x0301, 0x08);
+       err += zc0301_write_reg(cam, 0x018D, 0x70);
+       err += zc0301_write_reg(cam, 0x0008, 0x03);
+       err += zc0301_write_reg(cam, 0x01C6, 0x04);
+       err += zc0301_write_reg(cam, 0x01CB, 0x07);
+       err += zc0301_write_reg(cam, 0x0120, 0x11);
+       err += zc0301_write_reg(cam, 0x0121, 0x37);
+       err += zc0301_write_reg(cam, 0x0122, 0x58);
+       err += zc0301_write_reg(cam, 0x0123, 0x79);
+       err += zc0301_write_reg(cam, 0x0124, 0x91);
+       err += zc0301_write_reg(cam, 0x0125, 0xA6);
+       err += zc0301_write_reg(cam, 0x0126, 0xB8);
+       err += zc0301_write_reg(cam, 0x0127, 0xC7);
+       err += zc0301_write_reg(cam, 0x0128, 0xD3);
+       err += zc0301_write_reg(cam, 0x0129, 0xDE);
+       err += zc0301_write_reg(cam, 0x012A, 0xE6);
+       err += zc0301_write_reg(cam, 0x012B, 0xED);
+       err += zc0301_write_reg(cam, 0x012C, 0xF3);
+       err += zc0301_write_reg(cam, 0x012D, 0xF8);
+       err += zc0301_write_reg(cam, 0x012E, 0xFB);
+       err += zc0301_write_reg(cam, 0x012F, 0xFF);
+       err += zc0301_write_reg(cam, 0x0130, 0x26);
+       err += zc0301_write_reg(cam, 0x0131, 0x23);
+       err += zc0301_write_reg(cam, 0x0132, 0x20);
+       err += zc0301_write_reg(cam, 0x0133, 0x1C);
+       err += zc0301_write_reg(cam, 0x0134, 0x16);
+       err += zc0301_write_reg(cam, 0x0135, 0x13);
+       err += zc0301_write_reg(cam, 0x0136, 0x10);
+       err += zc0301_write_reg(cam, 0x0137, 0x0D);
+       err += zc0301_write_reg(cam, 0x0138, 0x0B);
+       err += zc0301_write_reg(cam, 0x0139, 0x09);
+       err += zc0301_write_reg(cam, 0x013A, 0x07);
+       err += zc0301_write_reg(cam, 0x013B, 0x06);
+       err += zc0301_write_reg(cam, 0x013C, 0x05);
+       err += zc0301_write_reg(cam, 0x013D, 0x04);
+       err += zc0301_write_reg(cam, 0x013E, 0x03);
+       err += zc0301_write_reg(cam, 0x013F, 0x02);
+       err += zc0301_write_reg(cam, 0x010A, 0x4C);
+       err += zc0301_write_reg(cam, 0x010B, 0xF5);
+       err += zc0301_write_reg(cam, 0x010C, 0xFF);
+       err += zc0301_write_reg(cam, 0x010D, 0xF9);
+       err += zc0301_write_reg(cam, 0x010E, 0x51);
+       err += zc0301_write_reg(cam, 0x010F, 0xF5);
+       err += zc0301_write_reg(cam, 0x0110, 0xFB);
+       err += zc0301_write_reg(cam, 0x0111, 0xED);
+       err += zc0301_write_reg(cam, 0x0112, 0x5F);
+       err += zc0301_write_reg(cam, 0x0180, 0x00);
+       err += zc0301_write_reg(cam, 0x0019, 0x00);
+       err += zc0301_write_reg(cam, 0x0087, 0x20);
+       err += zc0301_write_reg(cam, 0x0088, 0x21);
+
+       err += zc0301_i2c_write(cam, 0x20, 0x02);
+       err += zc0301_i2c_write(cam, 0x21, 0x1B);
+       err += zc0301_i2c_write(cam, 0x03, 0x44);
+       err += zc0301_i2c_write(cam, 0x0E, 0x01);
+       err += zc0301_i2c_write(cam, 0x0F, 0x00);
+
+       err += zc0301_write_reg(cam, 0x01A9, 0x14);
+       err += zc0301_write_reg(cam, 0x01AA, 0x24);
+       err += zc0301_write_reg(cam, 0x0190, 0x00);
+       err += zc0301_write_reg(cam, 0x0191, 0x02);
+       err += zc0301_write_reg(cam, 0x0192, 0x1B);
+       err += zc0301_write_reg(cam, 0x0195, 0x00);
+       err += zc0301_write_reg(cam, 0x0196, 0x00);
+       err += zc0301_write_reg(cam, 0x0197, 0x4D);
+       err += zc0301_write_reg(cam, 0x018C, 0x10);
+       err += zc0301_write_reg(cam, 0x018F, 0x20);
+       err += zc0301_write_reg(cam, 0x001D, 0x44);
+       err += zc0301_write_reg(cam, 0x001E, 0x6F);
+       err += zc0301_write_reg(cam, 0x001F, 0xAD);
+       err += zc0301_write_reg(cam, 0x0020, 0xEB);
+       err += zc0301_write_reg(cam, 0x0087, 0x0F);
+       err += zc0301_write_reg(cam, 0x0088, 0x0E);
+       err += zc0301_write_reg(cam, 0x0180, 0x40);
+       err += zc0301_write_reg(cam, 0x0192, 0x1B);
+       err += zc0301_write_reg(cam, 0x0191, 0x02);
+       err += zc0301_write_reg(cam, 0x0190, 0x00);
+       err += zc0301_write_reg(cam, 0x0116, 0x1D);
+       err += zc0301_write_reg(cam, 0x0117, 0x40);
+       err += zc0301_write_reg(cam, 0x0118, 0x99);
+       err += zc0301_write_reg(cam, 0x0180, 0x42);
+       err += zc0301_write_reg(cam, 0x0116, 0x1D);
+       err += zc0301_write_reg(cam, 0x0117, 0x40);
+       err += zc0301_write_reg(cam, 0x0118, 0x99);
+       err += zc0301_write_reg(cam, 0x0007, 0x00);
+
+       err += zc0301_i2c_write(cam, 0x11, 0x01);
+
+       msleep(100);
+
+       return err;
+}
+
+
+static int pas202bcb_get_ctrl(struct zc0301_device* cam,
+                              struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = zc0301_i2c_read(cam, 0x04, 1),
+                           r2 = zc0301_i2c_read(cam, 0x05, 1);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case ZC0301_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
+                       return -EIO;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int pas202bcb_set_ctrl(struct zc0301_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += zc0301_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += zc0301_i2c_write(cam, 0x07, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += zc0301_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case ZC0301_V4L2_CID_GREEN_BALANCE:
+               err += zc0301_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
+               err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += zc0301_i2c_write(cam, 0x11, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static struct zc0301_sensor pas202bcb = {
+       .name = "PAS202BCB",
+       .init = &pas202bcb_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x0001,
+                       .default_value = 0x01e5,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = ZC0301_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+       },
+       .get_ctrl = &pas202bcb_get_ctrl,
+       .set_ctrl = &pas202bcb_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_JPEG,
+               .priv = 8,
+       },
+};
+
+
+int zc0301_probe_pas202bcb(struct zc0301_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+       unsigned int pid = 0;
+
+       err += zc0301_write_reg(cam, 0x0000, 0x01);
+       err += zc0301_write_reg(cam, 0x0010, 0x0e);
+       err += zc0301_write_reg(cam, 0x0001, 0x01);
+       err += zc0301_write_reg(cam, 0x0012, 0x03);
+       err += zc0301_write_reg(cam, 0x0012, 0x01);
+       err += zc0301_write_reg(cam, 0x008d, 0x08);
+
+       msleep(10);
+
+       r0 = zc0301_i2c_read(cam, 0x00, 1);
+       r1 = zc0301_i2c_read(cam, 0x01, 1);
+
+       if (r0 < 0 || r1 < 0 || err)
+               return -EIO;
+
+       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
+       if (pid != 0x017)
+               return -ENODEV;
+
+       zc0301_attach_sensor(cam, &pas202bcb);
+
+       return 0;
+}
diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h
new file mode 100644 (file)
index 0000000..cf0965a
--- /dev/null
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * API for image sensors connected to the ZC030! Image Processor and       *
+ * Control Chip                                                            *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ZC0301_SENSOR_H_
+#define _ZC0301_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct zc0301_device;
+struct zc0301_sensor;
+
+/*****************************************************************************/
+
+extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+
+#define ZC0301_SENSOR_TABLE                                                   \
+/* Weak detections must go at the end of the list */                          \
+static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
+       &zc0301_probe_pas202bcb,                                              \
+       NULL,                                                                 \
+};
+
+extern struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
+
+extern void
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
+
+#define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+       .idVendor = (vend),                                                   \
+       .idProduct = (prod),                                                  \
+       .bInterfaceClass = (intclass)
+
+#define ZC0301_ID_TABLE                                                       \
+static const struct usb_device_id zc0301_id_table[] =  {                      \
+       { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), },                         \
+       { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */           \
+       { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
+       { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
+       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
+       { }                                                                   \
+};
+
+/*****************************************************************************/
+
+extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
+extern int zc0301_read_reg(struct zc0301_device*, u16 index);
+extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
+extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
+
+/*****************************************************************************/
+
+#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
+#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+
+struct zc0301_sensor {
+       char name[32];
+
+       struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
+       struct v4l2_cropcap cropcap;
+       struct v4l2_pix_format pix_format;
+
+       int (*init)(struct zc0301_device*);
+       int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct zc0301_device*,
+                       const struct v4l2_control* ctrl);
+       int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
+
+       /* Private */
+       struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
+       struct v4l2_rect _rect;
+};
+
+#endif /* _ZC0301_SENSOR_H_ */
index ad2f4cc..1fef36e 100644 (file)
@@ -570,10 +570,9 @@ static int auerchain_setup (pauerchain_t acp, unsigned int numElements)
 
         /* fill the list of free elements */
         for (;numElements; numElements--) {
-                acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL);
+                acep = kzalloc(sizeof(auerchainelement_t), GFP_KERNEL);
                 if (!acep)
                        goto ac_fail;
-               memset (acep, 0, sizeof (auerchainelement_t));
                 INIT_LIST_HEAD (&acep->list);
                 list_add_tail (&acep->list, &acp->free_list);
         }
@@ -761,10 +760,9 @@ static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned
 
         /* fill the list of free elements */
         for (;numElements; numElements--) {
-                bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL);
+                bep = kzalloc(sizeof(auerbuf_t), GFP_KERNEL);
                 if (!bep)
                        goto bl_fail;
-               memset (bep, 0, sizeof (auerbuf_t));
                 bep->list = bcp;
                 INIT_LIST_HEAD (&bep->buff_list);
                 bep->bufp = kmalloc (bufsize, GFP_KERNEL);
index 6671317..a042042 100644 (file)
@@ -351,12 +351,11 @@ static int cytherm_probe(struct usb_interface *interface,
        struct usb_cytherm *dev = NULL;
        int retval = -ENOMEM;
 
-       dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
+       dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
        if (dev == NULL) {
                dev_err (&interface->dev, "Out of memory\n");
                goto error;
        }
-       memset (dev, 0x00, sizeof (*dev));
 
        dev->udev = usb_get_dev(udev);
 
index d8cde10..d0b1672 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 
@@ -121,7 +122,7 @@ static struct usb_driver idmouse_driver = {
 };
 
 /* prevent races between open() and disconnect() */
-static DECLARE_MUTEX(disconnect_sem);
+static DEFINE_MUTEX(disconnect_mutex);
 
 static int idmouse_create_image(struct usb_idmouse *dev)
 {
@@ -213,18 +214,18 @@ static int idmouse_open(struct inode *inode, struct file *file)
        int result = 0;
 
        /* prevent disconnects */
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        /* get the interface from minor number and driver information */
        interface = usb_find_interface (&idmouse_driver, iminor (inode));
        if (!interface) {
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
        /* get the device information block from the interface */
        dev = usb_get_intfdata(interface);
        if (!dev) {
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
@@ -258,7 +259,7 @@ error:
        up(&dev->sem);
 
        /* unlock the disconnect semaphore */
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
        return result;
 }
 
@@ -267,12 +268,12 @@ static int idmouse_release(struct inode *inode, struct file *file)
        struct usb_idmouse *dev;
 
        /* prevent a race condition with open() */
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        dev = (struct usb_idmouse *) file->private_data;
 
        if (dev == NULL) {
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
@@ -282,7 +283,7 @@ static int idmouse_release(struct inode *inode, struct file *file)
        /* are we really open? */
        if (dev->open <= 0) {
                up(&dev->sem);
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
@@ -292,12 +293,12 @@ static int idmouse_release(struct inode *inode, struct file *file)
                /* the device was unplugged before the file was released */
                up(&dev->sem);
                idmouse_delete(dev);
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return 0;
        }
 
        up(&dev->sem);
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
        return 0;
 }
 
@@ -340,10 +341,9 @@ static int idmouse_probe(struct usb_interface *interface,
                return -ENODEV;
 
        /* allocate memory for our device state and initialize it */
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL)
                return -ENOMEM;
-       memset(dev, 0x00, sizeof(*dev));
 
        init_MUTEX(&dev->sem);
        dev->udev = udev;
@@ -400,7 +400,7 @@ static void idmouse_disconnect(struct usb_interface *interface)
        struct usb_idmouse *dev;
 
        /* prevent races with open() */
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        /* get device structure */
        dev = usb_get_intfdata(interface);
@@ -422,7 +422,7 @@ static void idmouse_disconnect(struct usb_interface *interface)
        if (!dev->open)
                idmouse_delete(dev);
 
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
 
        info("%s disconnected", DRIVER_DESC);
 }
index e2d1198..966acb4 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <linux/input.h>
@@ -172,7 +173,7 @@ struct ld_usb {
 };
 
 /* prevent races between open() and disconnect() */
-static DECLARE_MUTEX(disconnect_sem);
+static DEFINE_MUTEX(disconnect_mutex);
 
 static struct usb_driver ld_usb_driver;
 
@@ -293,7 +294,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
        nonseekable_open(inode, file);
        subminor = iminor(inode);
 
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        interface = usb_find_interface(&ld_usb_driver, subminor);
 
@@ -355,7 +356,7 @@ unlock_exit:
        up(&dev->sem);
 
 unlock_disconnect_exit:
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
 
        return retval;
 }
@@ -626,12 +627,11 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
 
        /* allocate memory for our device state and intialize it */
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                dev_err(&intf->dev, "Out of memory\n");
                goto exit;
        }
-       memset(dev, 0x00, sizeof(*dev));
        init_MUTEX(&dev->sem);
        dev->intf = intf;
        init_waitqueue_head(&dev->read_wait);
@@ -741,7 +741,7 @@ static void ld_usb_disconnect(struct usb_interface *intf)
        struct ld_usb *dev;
        int minor;
 
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        dev = usb_get_intfdata(intf);
        usb_set_intfdata(intf, NULL);
@@ -762,7 +762,7 @@ static void ld_usb_disconnect(struct usb_interface *intf)
                up(&dev->sem);
        }
 
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
 
        dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
                 (minor - USB_LD_MINOR_BASE));
index 1336745..779bcf0 100644 (file)
@@ -83,6 +83,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/poll.h>
@@ -256,7 +257,7 @@ static void tower_disconnect        (struct usb_interface *interface);
 
 
 /* prevent races between open() and disconnect */
-static DECLARE_MUTEX (disconnect_sem);
+static DEFINE_MUTEX (disconnect_mutex);
 
 /* file operations needed when we register this driver */
 static struct file_operations tower_fops = {
@@ -349,7 +350,7 @@ static int tower_open (struct inode *inode, struct file *file)
        nonseekable_open(inode, file);
        subminor = iminor(inode);
 
-       down (&disconnect_sem);
+       mutex_lock (&disconnect_mutex);
 
        interface = usb_find_interface (&tower_driver, subminor);
 
@@ -427,7 +428,7 @@ unlock_exit:
        up (&dev->sem);
 
 unlock_disconnect_exit:
-       up (&disconnect_sem);
+       mutex_unlock (&disconnect_mutex);
 
        dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
 
@@ -1005,7 +1006,7 @@ static void tower_disconnect (struct usb_interface *interface)
 
        dbg(2, "%s: enter", __FUNCTION__);
 
-       down (&disconnect_sem);
+       mutex_lock (&disconnect_mutex);
 
        dev = usb_get_intfdata (interface);
        usb_set_intfdata (interface, NULL);
@@ -1027,7 +1028,7 @@ static void tower_disconnect (struct usb_interface *interface)
                up (&dev->sem);
        }
 
-       up (&disconnect_sem);
+       mutex_unlock (&disconnect_mutex);
 
        info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
 
index 605a3c8..997db5d 100644 (file)
@@ -88,7 +88,7 @@ static int change_outputs(struct phidget_interfacekit *kit, int output_num, int
        int retval;
        int n;
 
-       buffer = kmalloc(4, GFP_KERNEL);
+       buffer = kzalloc(4, GFP_KERNEL);
        if (!buffer) {
                dev_err(&kit->udev->dev, "%s - out of memory\n",
                        __FUNCTION__);
@@ -96,7 +96,6 @@ static int change_outputs(struct phidget_interfacekit *kit, int output_num, int
        }
 
        kit->outputs[output_num] = enable;
-       memset(buffer, 0, 4);
        for (n=0; n<8; n++) {
                if (kit->outputs[n]) {
                        buffer[0] |= 1 << n;
@@ -192,7 +191,7 @@ static ssize_t set_backlight(struct device *dev, struct device_attribute *attr,
        unsigned char *buffer;
        int retval = -ENOMEM;
        
-       buffer = kmalloc(8, GFP_KERNEL);
+       buffer = kzalloc(8, GFP_KERNEL);
        if (!buffer) {
                dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
                goto exit;
@@ -202,7 +201,6 @@ static ssize_t set_backlight(struct device *dev, struct device_attribute *attr,
                retval = -EINVAL;
                goto exit;
        }
-       memset(buffer, 0x00, 8);
        if (enabled)
                buffer[0] = 0x01;
        buffer[7] = 0x11;
@@ -406,12 +404,11 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
        pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
        maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
        
-       kit = kmalloc(sizeof(*kit), GFP_KERNEL);
+       kit = kzalloc(sizeof(*kit), GFP_KERNEL);
        if (kit  == NULL) {
                dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset(kit, 0, sizeof(*kit));
        kit->ifkit = ifkit;
 
        kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma);
index b3418d2..5a040c2 100644 (file)
@@ -252,12 +252,11 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
        struct usb_device *udev = interface_to_usbdev(interface);
        struct phidget_servo *dev;
 
-       dev = kmalloc(sizeof (struct phidget_servo), GFP_KERNEL);
+       dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
        if (dev == NULL) {
                dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset(dev, 0x00, sizeof (*dev));
 
        dev->udev = usb_get_dev(udev);
        dev->type = id->driver_info;
index 3260d59..196c879 100644 (file)
@@ -3188,7 +3188,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        break;
 
                default:
-                       retval = -EINVAL;
+                       retval = -ENOTTY;
                        break;
        }
 
@@ -3251,12 +3251,11 @@ static int sisusb_probe(struct usb_interface *intf,
                dev->devnum);
 
        /* Allocate memory for our private */
-       if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) {
+       if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
                printk(KERN_ERR
                        "sisusb: Failed to allocate memory for private data\n");
                return -ENOMEM;
        }
-       memset(sisusb, 0, sizeof(*sisusb));
        kref_init(&sisusb->kref);
 
        init_MUTEX(&(sisusb->lock));
index 1d7a77c..a716825 100644 (file)
 #ifndef _SISUSB_H_
 #define _SISUSB_H_
 
-#include <linux/version.h>
 #ifdef CONFIG_COMPAT
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
-#include <linux/ioctl32.h>
-#define SISUSB_OLD_CONFIG_COMPAT
-#else
 #define SISUSB_NEW_CONFIG_COMPAT
 #endif
-#endif
 
 /* For older kernels, support for text consoles is by default
  * off. To ensable text console support, change the following:
  */
 #if 0
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
 #define CONFIG_USB_SISUSBVGA_CON
 #endif
-#endif
 
 /* Version Information */
 
index cc3dae3..c82c402 100644 (file)
@@ -270,12 +270,11 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
        int retval = -ENOMEM;
 
        /* allocate memory for our device state and initialize it */
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                err("Out of memory");
                goto error;
        }
-       memset(dev, 0x00, sizeof(*dev));
        kref_init(&dev->kref);
 
        dev->udev = usb_get_dev(interface_to_usbdev(interface));
index 877b081..f441964 100644 (file)
@@ -106,12 +106,11 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
        struct usb_led *dev = NULL;
        int retval = -ENOMEM;
 
-       dev = kmalloc(sizeof(struct usb_led), GFP_KERNEL);
+       dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
        if (dev == NULL) {
                dev_err(&interface->dev, "Out of memory\n");
                goto error;
        }
-       memset (dev, 0x00, sizeof (*dev));
 
        dev->udev = usb_get_dev(udev);
 
index 84fa172..9d59b90 100644 (file)
@@ -382,12 +382,11 @@ alloc_sglist (int nents, int max, int vary)
        for (i = 0; i < nents; i++) {
                char            *buf;
 
-               buf = kmalloc (size, SLAB_KERNEL);
+               buf = kzalloc (size, SLAB_KERNEL);
                if (!buf) {
                        free_sglist (sg, i);
                        return NULL;
                }
-               memset (buf, 0, size);
 
                /* kmalloc pages are always physically contiguous! */
                sg_init_one(&sg[i], buf, size);
@@ -842,10 +841,9 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
         * as with bulk/intr sglists, sglen is the queue depth; it also
         * controls which subtests run (more tests than sglen) or rerun.
         */
-       urb = kmalloc (param->sglen * sizeof (struct urb *), SLAB_KERNEL);
+       urb = kcalloc(param->sglen, sizeof(struct urb *), SLAB_KERNEL);
        if (!urb)
                return -ENOMEM;
-       memset (urb, 0, param->sglen * sizeof (struct urb *));
        for (i = 0; i < param->sglen; i++) {
                int                     pipe = usb_rcvctrlpipe (udev, 0);
                unsigned                len;
@@ -1865,10 +1863,9 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
        }
 #endif
 
-       dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+       dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
        if (!dev)
                return -ENOMEM;
-       memset (dev, 0, sizeof *dev);
        info = (struct usbtest_info *) id->driver_info;
        dev->info = info;
        init_MUTEX (&dev->sem);
index c34944c..6ecc273 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/debugfs.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
+#include <linux/mutex.h>
 
 #include "usb_mon.h"
 #include "../core/hcd.h"
@@ -23,7 +24,7 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
 static void mon_bus_drop(struct kref *r);
 static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
 
-DECLARE_MUTEX(mon_lock);
+DEFINE_MUTEX(mon_lock);
 
 static struct dentry *mon_dir;         /* /dbg/usbmon */
 static LIST_HEAD(mon_buses);           /* All buses we know: struct mon_bus */
@@ -196,14 +197,14 @@ static void mon_bus_remove(struct usb_bus *ubus)
 {
        struct mon_bus *mbus = ubus->mon_bus;
 
-       down(&mon_lock);
+       mutex_lock(&mon_lock);
        list_del(&mbus->bus_link);
        debugfs_remove(mbus->dent_t);
        debugfs_remove(mbus->dent_s);
 
        mon_dissolve(mbus, ubus);
        kref_put(&mbus->ref, mon_bus_drop);
-       up(&mon_lock);
+       mutex_unlock(&mon_lock);
 }
 
 static int mon_notify(struct notifier_block *self, unsigned long action,
@@ -276,9 +277,8 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
        char name[NAMESZ];
        int rc;
 
-       if ((mbus = kmalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
+       if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
                goto err_alloc;
-       memset(mbus, 0, sizeof(struct mon_bus));
        kref_init(&mbus->ref);
        spin_lock_init(&mbus->lock);
        INIT_LIST_HEAD(&mbus->r_list);
@@ -307,9 +307,9 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
                goto err_create_s;
        mbus->dent_s = d;
 
-       down(&mon_lock);
+       mutex_lock(&mon_lock);
        list_add_tail(&mbus->bus_link, &mon_buses);
-       up(&mon_lock);
+       mutex_unlock(&mon_lock);
        return;
 
 err_create_s:
@@ -347,11 +347,11 @@ static int __init mon_init(void)
 
        usb_register_notify(&mon_nb);
 
-       down(&usb_bus_list_lock);
+       mutex_lock(&usb_bus_list_lock);
        list_for_each_entry (ubus, &usb_bus_list, bus_list) {
                mon_bus_init(mondir, ubus);
        }
-       up(&usb_bus_list_lock);
+       mutex_unlock(&usb_bus_list_lock);
        return 0;
 }
 
@@ -363,7 +363,7 @@ static void __exit mon_exit(void)
        usb_unregister_notify(&mon_nb);
        usb_mon_deregister();
 
-       down(&mon_lock);
+       mutex_lock(&mon_lock);
        while (!list_empty(&mon_buses)) {
                p = mon_buses.next;
                mbus = list_entry(p, struct mon_bus, bus_link);
@@ -387,7 +387,7 @@ static void __exit mon_exit(void)
                mon_dissolve(mbus, mbus->u_bus);
                kref_put(&mbus->ref, mon_bus_drop);
        }
-       up(&mon_lock);
+       mutex_unlock(&mon_lock);
 
        debugfs_remove(mon_dir);
 }
index 6116121..ac043ec 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/list.h>
 #include <linux/usb.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "usb_mon.h"
@@ -54,7 +55,7 @@ struct mon_reader_text {
        wait_queue_head_t wait;
        int printf_size;
        char *printf_buf;
-       struct semaphore printf_lock;
+       struct mutex printf_lock;
 
        char slab_name[SLAB_NAME_SZ];
 };
@@ -208,19 +209,18 @@ static int mon_text_open(struct inode *inode, struct file *file)
        struct mon_reader_text *rp;
        int rc;
 
-       down(&mon_lock);
+       mutex_lock(&mon_lock);
        mbus = inode->u.generic_ip;
        ubus = mbus->u_bus;
 
-       rp = kmalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
+       rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
        if (rp == NULL) {
                rc = -ENOMEM;
                goto err_alloc;
        }
-       memset(rp, 0, sizeof(struct mon_reader_text));
        INIT_LIST_HEAD(&rp->e_list);
        init_waitqueue_head(&rp->wait);
-       init_MUTEX(&rp->printf_lock);
+       mutex_init(&rp->printf_lock);
 
        rp->printf_size = PRINTF_DFL;
        rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL);
@@ -247,7 +247,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
        mon_reader_add(mbus, &rp->r);
 
        file->private_data = rp;
-       up(&mon_lock);
+       mutex_unlock(&mon_lock);
        return 0;
 
 // err_busy:
@@ -257,7 +257,7 @@ err_slab:
 err_alloc_pr:
        kfree(rp);
 err_alloc:
-       up(&mon_lock);
+       mutex_unlock(&mon_lock);
        return rc;
 }
 
@@ -301,7 +301,7 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&rp->wait, &waita);
 
-       down(&rp->printf_lock);
+       mutex_lock(&rp->printf_lock);
        cnt = 0;
        pbuf = rp->printf_buf;
        limit = rp->printf_size;
@@ -358,7 +358,7 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
 
        if (copy_to_user(buf, rp->printf_buf, cnt))
                cnt = -EFAULT;
-       up(&rp->printf_lock);
+       mutex_unlock(&rp->printf_lock);
        kmem_cache_free(rp->e_slab, ep);
        return cnt;
 }
@@ -371,12 +371,12 @@ static int mon_text_release(struct inode *inode, struct file *file)
        struct list_head *p;
        struct mon_event_text *ep;
 
-       down(&mon_lock);
+       mutex_lock(&mon_lock);
        mbus = inode->u.generic_ip;
 
        if (mbus->nreaders <= 0) {
                printk(KERN_ERR TAG ": consistency error on close\n");
-               up(&mon_lock);
+               mutex_unlock(&mon_lock);
                return 0;
        }
        mon_reader_del(mbus, &rp->r);
@@ -402,7 +402,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
        kfree(rp->printf_buf);
        kfree(rp);
 
-       up(&mon_lock);
+       mutex_unlock(&mon_lock);
        return 0;
 }
 
index 4be0f93..8e0613c 100644 (file)
@@ -49,7 +49,7 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
  */
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
 
-extern struct semaphore mon_lock;
+extern struct mutex mon_lock;
 
 extern struct file_operations mon_fops_text;
 extern struct file_operations mon_fops_stat;
index 156a2f1..5b66756 100644 (file)
@@ -524,6 +524,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
        ret = set_registers(pegasus, EthCtrl0, 3, data);
 
        if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
+           usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 ||
            usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
                u16 auxmode;
                read_mii_word(pegasus, 0, 0x1b, &auxmode);
index 9fbd59b..a54752c 100644 (file)
@@ -25,7 +25,6 @@
 #define        PHY_READ                0x40
 #define        PHY_WRITE               0x20
 #define        DEFAULT_GPIO_RESET      0x24
-#define        LINKSYS_GPIO_RESET      0x24
 #define        DEFAULT_GPIO_SET        0x26
 
 #define        PEGASUS_PRESENT         0x00000001
@@ -140,6 +139,7 @@ struct usb_eth_dev {
 #define        VENDOR_KINGSTON         0x0951
 #define        VENDOR_LANEED           0x056e
 #define        VENDOR_LINKSYS          0x066b
+#define        VENDOR_LINKSYS2         0x077b
 #define        VENDOR_MELCO            0x0411
 #define        VENDOR_MICROSOFT        0x045e
 #define        VENDOR_MOBILITY         0x1342
@@ -218,15 +218,15 @@ PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
 PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
                DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
-               LINKSYS_GPIO_RESET )
+               DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
-               LINKSYS_GPIO_RESET )
+               DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
-               LINKSYS_GPIO_RESET | PEGASUS_II )
+               DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
-               LINKSYS_GPIO_RESET | PEGASUS_II )
+               DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
-               LINKSYS_GPIO_RESET | PEGASUS_II )
+               DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
                DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
@@ -260,17 +260,19 @@ PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
                DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
-               LINKSYS_GPIO_RESET )
+               DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
-               LINKSYS_GPIO_RESET )
+               DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
-               LINKSYS_GPIO_RESET | HAS_HOME_PNA )
+               DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
-               LINKSYS_GPIO_RESET | PEGASUS_II)
+               DEFAULT_GPIO_RESET | PEGASUS_II)
+PEGASUS_DEV( "Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4,
+               DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
-               LINKSYS_GPIO_RESET | PEGASUS_II )
+               DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
-               LINKSYS_GPIO_RESET | PEGASUS_II )       
+               DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
                DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
index 8ca52be..1bbbae2 100644 (file)
@@ -880,7 +880,6 @@ static int rtl8150_probe(struct usb_interface *intf,
        }
        fill_skb_pool(dev);
        set_ethernet_addr(dev);
-       info("%s: rtl8150 is detected", netdev->name);
        
        usb_set_intfdata(intf, dev);
        SET_NETDEV_DEV(netdev, &intf->dev);
@@ -888,6 +887,9 @@ static int rtl8150_probe(struct usb_interface *intf,
                err("couldn't register the device");
                goto out2;
        }
+
+       info("%s: rtl8150 is detected", netdev->name);
+
        return 0;
 
 out2:
index f3a8e28..fe9b60c 100644 (file)
@@ -621,10 +621,9 @@ static int zd1201_drvr_start(struct zd1201 *zd)
        __le16 zdmax;
        unsigned char *buffer;
        
-       buffer = kmalloc(ZD1201_RXSIZE, GFP_KERNEL);
+       buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
-       memset(buffer, 0, ZD1201_RXSIZE);
 
        usb_fill_bulk_urb(zd->rx_urb, zd->usb, 
            usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE,
@@ -1750,11 +1749,9 @@ static int zd1201_probe(struct usb_interface *interface,
 
        usb = interface_to_usbdev(interface);
 
-       zd = kmalloc(sizeof(struct zd1201), GFP_KERNEL);
-       if (!zd) {
+       zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL);
+       if (!zd)
                return -ENOMEM;
-       }
-       memset(zd, 0, sizeof(struct zd1201));
        zd->ap = ap;
        zd->usb = usb;
        zd->removed = 0;
index be5dc80..5a8a2c9 100644 (file)
@@ -403,6 +403,13 @@ config USB_SERIAL_MCT_U232
          To compile this driver as a module, choose M here: the
          module will be called mct_u232.
 
+config USB_SERIAL_NAVMAN
+       tristate "USB Navman GPS device"
+       depends on USB_SERIAL
+       help
+         To compile this driver as a module, choose M here: the
+         module will be called navman.
+
 config USB_SERIAL_PL2303
        tristate "USB Prolific 2303 Single Port Serial Driver"
        depends on USB_SERIAL
index f0b0442..f7fe417 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)          += keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_KLSI)                  += kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)             += kobil_sct.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)              += mct_u232.o
+obj-$(CONFIG_USB_SERIAL_NAVMAN)                        += navman.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)               += omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTION)                        += option.o
 obj-$(CONFIG_USB_SERIAL_PL2303)                        += pl2303.o
index dc7a069..e0c2acd 100644 (file)
@@ -32,7 +32,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.06"
+#define DRIVER_VERSION "v0.07"
 #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
 
 /*
@@ -58,6 +58,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
+       { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
        { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
        { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
        { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
@@ -169,9 +170,7 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request,
        /* Number of integers required to contain the array */
        length = (((size - 1) | 3) + 1)/4;
 
-       buf = kmalloc (length * sizeof(u32), GFP_KERNEL);
-       memset(buf, 0, length * sizeof(u32));
-
+       buf = kcalloc(length, sizeof(u32), GFP_KERNEL);
        if (!buf) {
                dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
                return -ENOMEM;
index 68067fe..7212fbe 100644 (file)
@@ -98,10 +98,16 @@ static struct usb_device_id id_table_cyphidcomrs232 [] = {
        { }                                             /* Terminating entry */
 };
 
+static struct usb_device_id id_table_nokiaca42v2 [] = {
+       { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
+       { }                                             /* Terminating entry */
+};
+
 static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
        { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
        { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+       { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
        { }                                             /* Terminating entry */
 };
 
@@ -149,6 +155,7 @@ struct cypress_buf {
 /* function prototypes for the Cypress USB to serial device */
 static int  cypress_earthmate_startup  (struct usb_serial *serial);
 static int  cypress_hidcom_startup     (struct usb_serial *serial);
+static int  cypress_ca42v2_startup     (struct usb_serial *serial);
 static void cypress_shutdown           (struct usb_serial *serial);
 static int  cypress_open               (struct usb_serial_port *port, struct file *filp);
 static void cypress_close              (struct usb_serial_port *port, struct file *filp);
@@ -235,6 +242,34 @@ static struct usb_serial_driver cypress_hidcom_device = {
        .write_int_callback =           cypress_write_int_callback,
 };
 
+static struct usb_serial_driver cypress_ca42v2_device = {
+       .driver = {
+               .owner =                THIS_MODULE,
+                .name =                        "nokiaca42v2",
+       },
+       .description =                  "Nokia CA-42 V2 Adapter",
+       .id_table =                     id_table_nokiaca42v2,
+       .num_interrupt_in =             1,
+       .num_interrupt_out =            1,
+       .num_bulk_in =                  NUM_DONT_CARE,
+       .num_bulk_out =                 NUM_DONT_CARE,
+       .num_ports =                    1,
+       .attach =                       cypress_ca42v2_startup,
+       .shutdown =                     cypress_shutdown,
+       .open =                         cypress_open,
+       .close =                        cypress_close,
+       .write =                        cypress_write,
+       .write_room =                   cypress_write_room,
+       .ioctl =                        cypress_ioctl,
+       .set_termios =                  cypress_set_termios,
+       .tiocmget =                     cypress_tiocmget,
+       .tiocmset =                     cypress_tiocmset,
+       .chars_in_buffer =              cypress_chars_in_buffer,
+       .throttle =                     cypress_throttle,
+       .unthrottle =                   cypress_unthrottle,
+       .read_int_callback =            cypress_read_int_callback,
+       .write_int_callback =           cypress_write_int_callback,
+};
 
 /*****************************************************************************
  * Cypress serial helper functions
@@ -286,6 +321,12 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
                                                    __FUNCTION__);
                                                new_baudrate = priv->baud_rate;
                                        }
+                               } else if (priv->chiptype == CT_CA42V2) {
+                                       if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+                                               err("%s - failed setting baud rate, unsupported speed",
+                                                   __FUNCTION__);
+                                               new_baudrate = priv->baud_rate;
+                                       }
                                } else if (priv->chiptype == CT_GENERIC) {
                                        if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
                                                err("%s - failed setting baud rate, unsupported speed",
@@ -435,11 +476,10 @@ static int generic_startup (struct usb_serial *serial)
 
        dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);
 
-       priv = kmalloc(sizeof (struct cypress_private), GFP_KERNEL);
+       priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       memset(priv, 0x00, sizeof (struct cypress_private));
        spin_lock_init(&priv->lock);
        priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
        if (priv->buf == NULL) {
@@ -500,6 +540,25 @@ static int cypress_hidcom_startup (struct usb_serial *serial)
 } /* cypress_hidcom_startup */
 
 
+static int cypress_ca42v2_startup (struct usb_serial *serial)
+{
+       struct cypress_private *priv;
+
+       dbg("%s", __FUNCTION__);
+
+       if (generic_startup(serial)) {
+               dbg("%s - Failed setting up port %d", __FUNCTION__,
+                               serial->port[0]->number);
+               return 1;
+       }
+
+       priv = usb_get_serial_port_data(serial->port[0]);
+       priv->chiptype = CT_CA42V2;
+
+       return 0;
+} /* cypress_ca42v2_startup */
+
+
 static void cypress_shutdown (struct usb_serial *serial)
 {
        struct cypress_private *priv;
@@ -944,6 +1003,10 @@ static void cypress_set_termios (struct usb_serial_port *port,
                        *(tty->termios) = tty_std_termios;
                        tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
                                CLOCAL;
+               } else if (priv->chiptype == CT_CA42V2) {
+                       *(tty->termios) = tty_std_termios;
+                       tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+                               CLOCAL;
                }
                priv->termios_initialized = 1;
        }
@@ -1542,6 +1605,9 @@ static int __init cypress_init(void)
        retval = usb_serial_register(&cypress_hidcom_device);
        if (retval)
                goto failed_hidcom_register;
+       retval = usb_serial_register(&cypress_ca42v2_device);
+       if (retval)
+               goto failed_ca42v2_register;
        retval = usb_register(&cypress_driver);
        if (retval)
                goto failed_usb_register;
@@ -1550,6 +1616,8 @@ static int __init cypress_init(void)
        return 0;
 failed_usb_register:
        usb_deregister(&cypress_driver);
+failed_ca42v2_register:
+       usb_serial_deregister(&cypress_ca42v2_device);
 failed_hidcom_register:
        usb_serial_deregister(&cypress_hidcom_device);
 failed_em_register:
@@ -1566,6 +1634,7 @@ static void __exit cypress_exit (void)
        usb_deregister (&cypress_driver);
        usb_serial_deregister (&cypress_earthmate_device);
        usb_serial_deregister (&cypress_hidcom_device);
+       usb_serial_deregister (&cypress_ca42v2_device);
 }
 
 
index 1fa119e..e1c7c27 100644 (file)
 /* Cypress HID->COM RS232 Adapter */
 #define VENDOR_ID_CYPRESS               0x04b4
 #define PRODUCT_ID_CYPHIDCOM            0x5500
+
+/* Nokia CA-42 USB to serial cable */
+#define VENDOR_ID_DAZZLE               0x07d0
+#define PRODUCT_ID_CA42                        0x4101
 /* End of device listing */
 
 /* Used for setting / requesting serial line settings */
@@ -34,6 +38,7 @@
 
 #define CT_EARTHMATE   0x01
 #define CT_CYPHIDCOM   0x02
+#define CT_CA42V2      0x03
 #define CT_GENERIC     0x0F
 /* End of chiptype definitions */
 
index c145e1e..f3af81b 100644 (file)
@@ -492,6 +492,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
+       { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -1141,12 +1142,11 @@ static int ftdi_sio_attach (struct usb_serial *serial)
        
        dbg("%s",__FUNCTION__);
 
-       priv = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+       priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
        if (!priv){
                err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
                return -ENOMEM;
        }
-       memset(priv, 0, sizeof(*priv));
 
        spin_lock_init(&priv->rx_lock);
         init_waitqueue_head(&priv->delta_msr_wait);
index bdef3b8..8da773c 100644 (file)
 #define KOBIL_CONV_KAAN_PID    0x2021  /* KOBIL_Konverter for KAAN */
 
 /*
+ * Icom ID-1 digital transceiver
+ */
+
+#define ICOM_ID1_VID            0x0C26
+#define ICOM_ID1_PID            0x0004
+
+/*
  * DSS-20 Sync Station for Sony Ericsson P800
  */
  
index d6f55e9..5ec9bf5 100644 (file)
@@ -1422,12 +1422,11 @@ static int garmin_attach (struct usb_serial *serial)
 
        dbg("%s", __FUNCTION__);
 
-       garmin_data_p = kmalloc (sizeof(struct garmin_data), GFP_KERNEL);
+       garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
        if (garmin_data_p == NULL) {
                dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset (garmin_data_p, 0, sizeof(struct garmin_data));
        init_timer(&garmin_data_p->timer);
        spin_lock_init(&garmin_data_p->lock);
        INIT_LIST_HEAD(&garmin_data_p->pktlist);
index 3f29e6b..b606c59 100644 (file)
@@ -2725,12 +2725,11 @@ static int edge_startup (struct usb_serial *serial)
        dev = serial->dev;
 
        /* create our private serial structure */
-       edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+       edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
        if (edge_serial == NULL) {
                dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset (edge_serial, 0, sizeof(struct edgeport_serial));
        spin_lock_init(&edge_serial->es_lock);
        edge_serial->serial = serial;
        usb_set_serial_data(serial, edge_serial);
index afc0f34..8e1e225 100644 (file)
@@ -2727,12 +2727,11 @@ static int edge_startup (struct usb_serial *serial)
        dev = serial->dev;
 
        /* create our private serial structure */
-       edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+       edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
        if (edge_serial == NULL) {
                dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset (edge_serial, 0, sizeof(struct edgeport_serial));
        sema_init(&edge_serial->es_sem, 1);
        edge_serial->serial = serial;
        usb_set_serial_data(serial, edge_serial);
@@ -2745,12 +2744,11 @@ static int edge_startup (struct usb_serial *serial)
 
        /* set up our port private structures */
        for (i = 0; i < serial->num_ports; ++i) {
-               edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
+               edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL);
                if (edge_port == NULL) {
                        dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
                        goto cleanup;
                }
-               memset (edge_port, 0, sizeof(struct edgeport_port));
                spin_lock_init(&edge_port->ep_lock);
                edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE);
                if (edge_port->ep_out_buf == NULL) {
index a590104..426182d 100644 (file)
@@ -184,10 +184,9 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev,
        struct irda_class_desc *desc;
        int ret;
                
-       desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
+       desc = kzalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
        if (desc == NULL) 
                return NULL;
-       memset(desc, 0, sizeof(struct irda_class_desc));
        
        ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
                        IU_REQ_GET_CLASS_DESC,
index 3b958e6..052b735 100644 (file)
@@ -2250,12 +2250,11 @@ static int keyspan_startup (struct usb_serial *serial)
        }
 
        /* Setup private data for serial driver */
-       s_priv = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
+       s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
        if (!s_priv) {
                dbg("%s - kmalloc for keyspan_serial_private failed.", __FUNCTION__);
                return -ENOMEM;
        }
-       memset(s_priv, 0, sizeof(struct keyspan_serial_private));
 
        s_priv->device_details = d_details;
        usb_set_serial_data(serial, s_priv);
@@ -2263,12 +2262,11 @@ static int keyspan_startup (struct usb_serial *serial)
        /* Now setup per port private data */
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
-               p_priv = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
+               p_priv = kzalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
                if (!p_priv) {
                        dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __FUNCTION__, i);
                        return (1);
                }
-               memset(p_priv, 0, sizeof(struct keyspan_port_private));
                p_priv->device_details = d_details;
                usb_set_serial_port_data(port, p_priv);
        }
index b8b2131..87dfcd8 100644 (file)
@@ -255,11 +255,9 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
        }
        
        // allocate memory for transfer buffer
-       transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+       transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (! transfer_buffer) {
                return -ENOMEM;
-       } else {
-               memset(transfer_buffer, 0, transfer_buffer_length);
        }
        
        // allocate write_urb
@@ -383,11 +381,10 @@ static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
                
                // BEGIN DEBUG
                /*
-                 dbg_data = (unsigned char *) kmalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
+                 dbg_data = kzalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
                  if (! dbg_data) {
                  return;
                  }
-                 memset(dbg_data, 0, (3 *  purb->actual_length + 10));
                  for (i = 0; i < purb->actual_length; i++) { 
                  sprintf(dbg_data +3*i, "%02X ", data[i]); 
                  }
@@ -518,11 +515,10 @@ static int kobil_tiocmget(struct usb_serial_port *port, struct file *file)
        }
 
        // allocate memory for transfer buffer
-       transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+       transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (!transfer_buffer) {
                return -ENOMEM;
        }
-       memset(transfer_buffer, 0, transfer_buffer_length);
 
        result = usb_control_msg( port->serial->dev, 
                                  usb_rcvctrlpipe(port->serial->dev, 0 ), 
@@ -564,11 +560,10 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
        }
 
        // allocate memory for transfer buffer
-       transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);
+       transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (! transfer_buffer) {
                return -ENOMEM;
        }
-       memset(transfer_buffer, 0, transfer_buffer_length);
 
        if (set & TIOCM_RTS)
                rts = 1;
@@ -655,11 +650,10 @@ static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
                                                   (struct termios __user *)arg))
                        return -EFAULT;
                
-               settings = (unsigned char *) kmalloc(50, GFP_KERNEL);  
+               settings = kzalloc(50, GFP_KERNEL);
                if (! settings) {
                        return -ENOBUFS;
                }
-               memset(settings, 0, 50);
 
                switch (priv->internal_termios.c_cflag & CBAUD) {
                case B1200:
index b6d6cab..35bd29b 100644 (file)
@@ -348,10 +348,9 @@ static int mct_u232_startup (struct usb_serial *serial)
        struct mct_u232_private *priv;
        struct usb_serial_port *port, *rport;
 
-       priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
+       priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
-       memset(priv, 0, sizeof(struct mct_u232_private));
        spin_lock_init(&priv->lock);
        usb_set_serial_port_data(serial->port[0], priv);
 
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
new file mode 100644 (file)
index 0000000..7f54408
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Navman Serial USB driver
+ *
+ * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ *     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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */
+       { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver navman_driver = {
+       .name =         "navman",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table,
+       .no_dynamic_id =        1,
+};
+
+static void navman_read_int_callback(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_serial_port *port = urb->context;
+       unsigned char *data = urb->transfer_buffer;
+       struct tty_struct *tty;
+       int result;
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d",
+                   __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d",
+                   __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+                             urb->actual_length, data);
+
+       tty = port->tty;
+       if (tty && urb->actual_length) {
+               tty_buffer_request_room(tty, urb->actual_length);
+               tty_insert_flip_string(tty, data, urb->actual_length);
+               tty_flip_buffer_push(tty);
+       }
+
+exit:
+       result = usb_submit_urb(urb, GFP_ATOMIC);
+       if (result)
+               dev_err(&urb->dev->dev,
+                       "%s - Error %d submitting interrupt urb\n",
+                       __FUNCTION__, result);
+}
+
+static int navman_open(struct usb_serial_port *port, struct file *filp)
+{
+       int result = 0;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (port->interrupt_in_urb) {
+               dbg("%s - adding interrupt input for treo", __FUNCTION__);
+               result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+               if (result)
+                       dev_err(&port->dev,
+                               "%s - failed submitting interrupt urb, error %d\n",
+                               __FUNCTION__, result);
+       }
+       return result;
+}
+
+static void navman_close(struct usb_serial_port *port, struct file *filp)
+{
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (port->interrupt_in_urb)
+               usb_kill_urb(port->interrupt_in_urb);
+}
+
+static int navman_write(struct usb_serial_port *port,
+                       const unsigned char *buf, int count)
+{
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       /*
+        * This device can't write any data, only read from the device
+        * so we just silently eat all data sent to us and say it was
+        * successfully sent.
+        * Evil, I know, but do you have a better idea?
+        */
+
+       return count;
+}
+
+static struct usb_serial_driver navman_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "navman",
+       },
+       .id_table =             id_table,
+       .num_interrupt_in =     NUM_DONT_CARE,
+       .num_bulk_in =          NUM_DONT_CARE,
+       .num_bulk_out =         NUM_DONT_CARE,
+       .num_ports =            1,
+       .open =                 navman_open,
+       .close =                navman_close,
+       .write =                navman_write,
+       .read_int_callback =    navman_read_int_callback,
+};
+
+static int __init navman_init(void)
+{
+       int retval;
+
+       retval = usb_serial_register(&navman_device);
+       if (retval)
+               return retval;
+       retval = usb_register(&navman_driver);
+       if (retval)
+               usb_serial_deregister(&navman_device);
+       return retval;
+}
+
+static void __exit navman_exit(void)
+{
+       usb_deregister(&navman_driver);
+       usb_serial_deregister(&navman_device);
+}
+
+module_init(navman_init);
+module_exit(navman_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
index 762d8ff..4d40704 100644 (file)
@@ -204,7 +204,7 @@ static void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
        int i;
        int result;
 
-//     dbg("omninet_read_bulk_callback");
+       dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (urb->status) {
                dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
@@ -250,7 +250,7 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
 
        int                     result;
 
-//     dbg("omninet_write port %d", port->number);
+       dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (count == 0) {
                dbg("%s - write request of 0 bytes", __FUNCTION__);
@@ -302,7 +302,7 @@ static int omninet_write_room (struct usb_serial_port *port)
        if (wport->write_urb_busy)
                room = wport->bulk_out_size - OMNINET_HEADERLEN;
 
-//     dbg("omninet_write_room returns %d", room);
+       dbg("%s - returns %d", __FUNCTION__, room);
 
        return (room);
 }
@@ -312,7 +312,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
 /*     struct omninet_header   *header = (struct omninet_header  *) urb->transfer_buffer; */
        struct usb_serial_port  *port   = (struct usb_serial_port *) urb->context;
 
-//     dbg("omninet_write_bulk_callback, port %0x\n", port);
+       dbg("%s - port %0x\n", __FUNCTION__, port->number);
 
        port->write_urb_busy = 0;
        if (urb->status) {
@@ -321,8 +321,6 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
        }
 
        schedule_work(&port->work);
-
-//     dbg("omninet_write_bulk_callback, tty %0x\n", tty);
 }
 
 
index 52bdf6f..a8455c9 100644 (file)
@@ -631,13 +631,12 @@ static int option_startup(struct usb_serial *serial)
        /* Now setup per port private data */
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
-               portdata = kmalloc(sizeof(*portdata), GFP_KERNEL);
+               portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
                if (!portdata) {
                        dbg("%s: kmalloc for option_port_private (%d) failed!.",
                                        __FUNCTION__, i);
                        return (1);
                }
-               memset(portdata, 0, sizeof(struct option_port_private));
 
                usb_set_serial_port_data(port, portdata);
 
index 37c81c0..b3014fd 100644 (file)
@@ -77,6 +77,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
        { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
        { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
+       { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
 
@@ -218,10 +219,9 @@ static int pl2303_startup (struct usb_serial *serial)
        dbg("device type: %d", type);
 
        for (i = 0; i < serial->num_ports; ++i) {
-               priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL);
+               priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
                if (!priv)
                        goto cleanup;
-               memset (priv, 0x00, sizeof (struct pl2303_private));
                spin_lock_init(&priv->lock);
                priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
                if (priv->buf == NULL) {
@@ -383,12 +383,11 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
                }
        }
 
-       buf = kmalloc (7, GFP_KERNEL);
+       buf = kzalloc (7, GFP_KERNEL);
        if (!buf) {
                dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
                return;
        }
-       memset (buf, 0x00, 0x07);
        
        i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
                             GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
@@ -828,6 +827,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
        spin_lock_irqsave(&priv->lock, flags);
        priv->line_status = data[status_idx];
        spin_unlock_irqrestore(&priv->lock, flags);
+       wake_up_interruptible (&priv->delta_msr_wait);
 
 exit:
        return;
index 9bc4755..77901d1 100644 (file)
@@ -75,3 +75,7 @@
 /* Leadtek GPS 9531 (ID 0413:2101) */
 #define LEADTEK_VENDOR_ID      0x0413
 #define LEADTEK_9531_PRODUCT_ID        0x2101
+
+/* USB GSM cable from Speed Dragon Multimedia, Ltd */
+#define SPEEDDRAGON_VENDOR_ID  0x0e55
+#define SPEEDDRAGON_PRODUCT_ID 0x110b
index c18db32..c3a2071 100644 (file)
@@ -416,12 +416,11 @@ static int ti_startup(struct usb_serial *serial)
            dev->actconfig->desc.bConfigurationValue);
 
        /* create device structure */
-       tdev = kmalloc(sizeof(struct ti_device), GFP_KERNEL);
+       tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL);
        if (tdev == NULL) {
                dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       memset(tdev, 0, sizeof(struct ti_device));
        sema_init(&tdev->td_open_close_sem, 1);
        tdev->td_serial = serial;
        usb_set_serial_data(serial, tdev);
index b5c96e7..097f4e8 100644 (file)
@@ -564,12 +564,11 @@ static struct usb_serial * create_serial (struct usb_device *dev,
 {
        struct usb_serial *serial;
 
-       serial = kmalloc (sizeof (*serial), GFP_KERNEL);
+       serial = kzalloc(sizeof(*serial), GFP_KERNEL);
        if (!serial) {
                dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
                return NULL;
        }
-       memset (serial, 0, sizeof(*serial));
        serial->dev = usb_get_dev(dev);
        serial->type = driver;
        serial->interface = interface;
@@ -778,10 +777,9 @@ int usb_serial_probe(struct usb_interface *interface,
        serial->num_port_pointers = max_endpoints;
        dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
        for (i = 0; i < max_endpoints; ++i) {
-               port = kmalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
+               port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
                if (!port)
                        goto probe_error;
-               memset(port, 0x00, sizeof(struct usb_serial_port));
                port->number = i + serial->minor;
                port->serial = serial;
                spin_lock_init(&port->lock);
index 11a48d8..f5c3841 100644 (file)
@@ -763,10 +763,9 @@ static int generic_startup(struct usb_serial *serial)
        int i;
 
        for (i = 0; i < serial->num_ports; ++i) {
-               priv = kmalloc (sizeof(*priv), GFP_KERNEL);
+               priv = kzalloc (sizeof(*priv), GFP_KERNEL);
                if (!priv)
                        return -ENOMEM;
-               memset (priv, 0x00, sizeof(*priv));
                spin_lock_init(&priv->lock);
                usb_set_serial_port_data(serial->port[i], priv);
        }
index 54e3e6c..01d8971 100644 (file)
@@ -512,13 +512,12 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
        };
 
        if (!us->extra) {
-               us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO);
+               us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
                if (!us->extra) {
                        US_DEBUGP("datafab_transport:  Gah! "
                                  "Can't allocate storage for Datafab info struct!\n");
                        return USB_STOR_TRANSPORT_ERROR;
                }
-               memset(us->extra, 0, sizeof(struct datafab_info));
                us->extra_destructor = datafab_info_destructor;
                ((struct datafab_info *)us->extra)->lun = -1;
        }
index ecb328a..6831dca 100644 (file)
@@ -1361,21 +1361,19 @@ static int isd200_init_info(struct us_data *us)
        struct isd200_info *info;
 
        info = (struct isd200_info *)
-                       kmalloc(sizeof(struct isd200_info), GFP_KERNEL);
+                       kzalloc(sizeof(struct isd200_info), GFP_KERNEL);
        if (!info)
                retStatus = ISD200_ERROR;
        else {
-               memset(info, 0, sizeof(struct isd200_info));
                info->id = (struct hd_driveid *)
-                               kmalloc(sizeof(struct hd_driveid), GFP_KERNEL);
+                               kzalloc(sizeof(struct hd_driveid), GFP_KERNEL);
                info->RegsBuf = (unsigned char *)
                                kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
                if (!info->id || !info->RegsBuf) {
                        isd200_free_info_ptrs(info);
                        kfree(info);
                        retStatus = ISD200_ERROR;
-               } else
-                       memset(info->id, 0, sizeof(struct hd_driveid));
+               }
        }
 
        if (retStatus == ISD200_GOOD) {
@@ -1384,7 +1382,7 @@ static int isd200_init_info(struct us_data *us)
        } else
                US_DEBUGP("ERROR - kmalloc failure\n");
 
-       return(retStatus);
+       return retStatus;
 }
 
 /**************************************************************************
index aff9d51..5031aa9 100644 (file)
@@ -441,12 +441,11 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
        };
 
        if (!us->extra) {
-               us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO);
+               us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO);
                if (!us->extra) {
                        US_DEBUGP("jumpshot_transport:  Gah! Can't allocate storage for jumpshot info struct!\n");
                        return USB_STOR_TRANSPORT_ERROR;
                }
-               memset(us->extra, 0, sizeof(struct jumpshot_info));
                us->extra_destructor = jumpshot_info_destructor;
        }
 
index 4ef5527..5f11e19 100644 (file)
@@ -47,6 +47,7 @@
 
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -271,9 +272,9 @@ static int device_reset(struct scsi_cmnd *srb)
        US_DEBUGP("%s called\n", __FUNCTION__);
 
        /* lock the device pointers and do the reset */
-       down(&(us->dev_semaphore));
+       mutex_lock(&(us->dev_mutex));
        result = us->transport_reset(us);
-       up(&(us->dev_semaphore));
+       mutex_unlock(&us->dev_mutex);
 
        return result < 0 ? FAILED : SUCCESS;
 }
@@ -286,9 +287,9 @@ static int bus_reset(struct scsi_cmnd *srb)
 
        US_DEBUGP("%s called\n", __FUNCTION__);
 
-       down(&(us->dev_semaphore));
+       mutex_lock(&(us->dev_mutex));
        result = usb_stor_port_reset(us);
-       up(&(us->dev_semaphore));
+       mutex_unlock(&us->dev_mutex);
 
        return result < 0 ? FAILED : SUCCESS;
 }
index 8451779..0b1b5b5 100644 (file)
@@ -751,11 +751,10 @@ int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
        struct sddr55_card_info *info;
 
        if (!us->extra) {
-               us->extra = kmalloc(
+               us->extra = kzalloc(
                        sizeof(struct sddr55_card_info), GFP_NOIO);
                if (!us->extra)
                        return USB_STOR_TRANSPORT_ERROR;
-               memset(us->extra, 0, sizeof(struct sddr55_card_info));
                us->extra_destructor = sddr55_card_info_destructor;
        }
 
index fea176d..f2bc5c9 100644 (file)
@@ -1318,12 +1318,11 @@ int init_usbat(struct us_data *us)
        unsigned char subcountL = USBAT_ATA_LBA_ME;
        unsigned char *status = us->iobuf;
 
-       us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO);
+       us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO);
        if (!us->extra) {
                US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
                return 1;
        }
-       memset(us->extra, 0, sizeof(struct usbat_info));
        info = (struct usbat_info *) (us->extra);
 
        /* Enable peripheral control signals */
index 31ca920..c4a9dcf 100644 (file)
@@ -62,6 +62,13 @@ UNUSUAL_DEV(  0x03ee, 0x6901, 0x0000, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_SINGLE_LUN ),
 
+/* Reported by Rodolfo Quesada <rquesada@roqz.net> */
+UNUSUAL_DEV(  0x03ee, 0x6906, 0x0003, 0x0003,
+               "VIA Technologies Inc.",
+               "Mitsumi multi cardreader",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_IGNORE_RESIDUE ),
+
 UNUSUAL_DEV(  0x03f0, 0x0107, 0x0200, 0x0200, 
                "HP",
                "CD-Writer+",
@@ -120,6 +127,12 @@ UNUSUAL_DEV(  0x0419, 0xaaf6, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Pete Zaitcev <zaitcev@redhat.com>, bz#176584 */
+UNUSUAL_DEV(  0x0420, 0x0001, 0x0100, 0x0100,
+               "GENERIC", "MP3 PLAYER", /* MyMusix PD-205 on the outside. */
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_IGNORE_RESIDUE ),
+
 /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
 UNUSUAL_DEV(  0x0424, 0x0fdc, 0x0210, 0x0210,
                "SMSC",
@@ -760,12 +773,19 @@ UNUSUAL_DEV(  0x069b, 0x3004, 0x0001, 0x0001,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY ),
 
-UNUSUAL_DEV(  0x0781, 0x0001, 0x0200, 0x0200, 
+/* Submitted by Roman Hodek <roman@hodek.net> */
+UNUSUAL_DEV(  0x0781, 0x0001, 0x0200, 0x0200,
                "Sandisk",
                "ImageMate SDDR-05a",
                US_SC_SCSI, US_PR_CB, NULL,
                US_FL_SINGLE_LUN ),
 
+UNUSUAL_DEV(  0x0781, 0x0002, 0x0009, 0x0009,
+               "SanDisk Corporation",
+               "ImageMate CompactFlash USB",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY ),
+
 #ifdef CONFIG_USB_STORAGE_USBAT
 UNUSUAL_DEV(  0x0781, 0x0005, 0x0005, 0x0005,
                "Sandisk",
@@ -1073,6 +1093,16 @@ UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
                        0),
 #endif
 
+/*
+ * Pete Zaitcev <zaitcev@yahoo.com>, bz#164688.
+ * The device blatantly ignores LUN and returns 1 in GetMaxLUN.
+ */
+UNUSUAL_DEV( 0x0c45, 0x1060, 0x0100, 0x0100,
+               "Unknown",
+               "Unknown",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_SINGLE_LUN ),
+
 /* Submitted by Joris Struyve <joris@struyve.be> */
 UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
                "Medion",
index dbcf239..dd10863 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -188,7 +189,7 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message)
        struct us_data *us = usb_get_intfdata(iface);
 
        /* Wait until no command is running */
-       down(&us->dev_semaphore);
+       mutex_lock(&us->dev_mutex);
 
        US_DEBUGP("%s\n", __FUNCTION__);
        if (us->suspend_resume_hook)
@@ -198,7 +199,7 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message)
        /* When runtime PM is working, we'll set a flag to indicate
         * whether we should autoresume when a SCSI request arrives. */
 
-       up(&us->dev_semaphore);
+       mutex_unlock(&us->dev_mutex);
        return 0;
 }
 
@@ -206,14 +207,14 @@ static int storage_resume(struct usb_interface *iface)
 {
        struct us_data *us = usb_get_intfdata(iface);
 
-       down(&us->dev_semaphore);
+       mutex_lock(&us->dev_mutex);
 
        US_DEBUGP("%s\n", __FUNCTION__);
        if (us->suspend_resume_hook)
                (us->suspend_resume_hook)(us, US_RESUME);
        iface->dev.power.power_state.event = PM_EVENT_ON;
 
-       up(&us->dev_semaphore);
+       mutex_unlock(&us->dev_mutex);
        return 0;
 }
 
@@ -276,12 +277,12 @@ static int usb_stor_control_thread(void * __us)
                US_DEBUGP("*** thread awakened.\n");
 
                /* lock the device pointers */
-               down(&(us->dev_semaphore));
+               mutex_lock(&(us->dev_mutex));
 
                /* if the device has disconnected, we are free to exit */
                if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
                        US_DEBUGP("-- exiting\n");
-                       up(&(us->dev_semaphore));
+                       mutex_unlock(&us->dev_mutex);
                        break;
                }
 
@@ -370,7 +371,7 @@ SkipForAbort:
                scsi_unlock(host);
 
                /* unlock the device pointers */
-               up(&(us->dev_semaphore));
+               mutex_unlock(&us->dev_mutex);
        } /* for (;;) */
 
        scsi_host_put(host);
@@ -815,8 +816,8 @@ static void quiesce_and_remove_host(struct us_data *us)
         * The thread will exit when it sees the DISCONNECTING flag. */
 
        /* Wait for the current command to finish, then remove the host */
-       down(&us->dev_semaphore);
-       up(&us->dev_semaphore);
+       mutex_lock(&us->dev_mutex);
+       mutex_unlock(&us->dev_mutex);
 
        /* queuecommand won't accept any new commands and the control
         * thread won't execute a previously-queued command.  If there
@@ -870,9 +871,9 @@ retry:
                /* For bulk-only devices, determine the max LUN value */
                if (us->protocol == US_PR_BULK &&
                                !(us->flags & US_FL_SINGLE_LUN)) {
-                       down(&us->dev_semaphore);
+                       mutex_lock(&us->dev_mutex);
                        us->max_lun = usb_stor_Bulk_max_lun(us);
-                       up(&us->dev_semaphore);
+                       mutex_unlock(&us->dev_mutex);
                }
                scsi_scan_host(us_to_host(us));
                printk(KERN_DEBUG "usb-storage: device scan complete\n");
@@ -912,7 +913,7 @@ static int storage_probe(struct usb_interface *intf,
 
        us = host_to_us(host);
        memset(us, 0, sizeof(struct us_data));
-       init_MUTEX(&(us->dev_semaphore));
+       mutex_init(&(us->dev_mutex));
        init_MUTEX_LOCKED(&(us->sema));
        init_completion(&(us->notify));
        init_waitqueue_head(&us->delay_wait);
index 7259fd1..009fb09 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/blkdev.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <scsi/scsi_host.h>
 
 struct us_data;
@@ -103,9 +104,9 @@ typedef void (*pm_hook)(struct us_data *, int);     /* power management hook */
 struct us_data {
        /* The device we're working with
         * It's important to note:
-        *    (o) you must hold dev_semaphore to change pusb_dev
+        *    (o) you must hold dev_mutex to change pusb_dev
         */
-       struct semaphore        dev_semaphore;   /* protect pusb_dev */
+       struct mutex            dev_mutex;       /* protect pusb_dev */
        struct usb_device       *pusb_dev;       /* this usb_device */
        struct usb_interface    *pusb_intf;      /* this interface */
        struct us_unusual_dev   *unusual_dev;    /* device-filter entry     */
index f5079c7..fdebd60 100644 (file)
@@ -899,8 +899,6 @@ config FB_RADEON_OLD
          Choose this option if you want to use an ATI Radeon graphics card as
          a framebuffer device.  There are both PCI and AGP versions.  You
          don't need to choose this to run the Radeon in plain VGA mode.
-         There is a product page at
-         <http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
 
 config FB_RADEON
        tristate "ATI Radeon display support"
index 3b0e713..0827594 100644 (file)
@@ -607,6 +607,7 @@ static void clearfb16(struct fb_info *info)
 
 static void epson1355fb_platform_release(struct device *device)
 {
+       dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
 }
 
 static int epson1355fb_remove(struct platform_device *dev)
index 8a893ce..d9831fd 100644 (file)
@@ -1457,7 +1457,7 @@ static int __init sa1100fb_probe(struct platform_device *pdev)
        int ret, irq;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0)
+       if (irq < 0)
                return -EINVAL;
 
        if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
index 53208cb..77eed1f 100644 (file)
@@ -401,6 +401,7 @@ static int __init vfb_setup(char *options)
 static void vfb_platform_release(struct device *device)
 {
        // This is called when the reference count goes to zero.
+       dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
 }
 
 static int __init vfb_probe(struct platform_device *dev)
index 21195c4..5c36345 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kobject.h>
 #include <linux/kobj_map.h>
 #include <linux/cdev.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -28,7 +29,7 @@ static struct kobj_map *cdev_map;
 
 #define MAX_PROBE_HASH 255     /* random */
 
-static DECLARE_MUTEX(chrdevs_lock);
+static DEFINE_MUTEX(chrdevs_lock);
 
 static struct char_device_struct {
        struct char_device_struct *next;
@@ -88,13 +89,13 @@ out:
 
 void *acquire_chrdev_list(void)
 {
-       down(&chrdevs_lock);
+       mutex_lock(&chrdevs_lock);
        return get_next_chrdev(NULL);
 }
 
 void release_chrdev_list(void *dev)
 {
-       up(&chrdevs_lock);
+       mutex_unlock(&chrdevs_lock);
        kfree(dev);
 }
 
@@ -151,7 +152,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
 
        memset(cd, 0, sizeof(struct char_device_struct));
 
-       down(&chrdevs_lock);
+       mutex_lock(&chrdevs_lock);
 
        /* temporary */
        if (major == 0) {
@@ -186,10 +187,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
        }
        cd->next = *cp;
        *cp = cd;
-       up(&chrdevs_lock);
+       mutex_unlock(&chrdevs_lock);
        return cd;
 out:
-       up(&chrdevs_lock);
+       mutex_unlock(&chrdevs_lock);
        kfree(cd);
        return ERR_PTR(ret);
 }
@@ -200,7 +201,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
        struct char_device_struct *cd = NULL, **cp;
        int i = major_to_index(major);
 
-       down(&chrdevs_lock);
+       mutex_lock(&chrdevs_lock);
        for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
                if ((*cp)->major == major &&
                    (*cp)->baseminor == baseminor &&
@@ -210,7 +211,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
                cd = *cp;
                *cp = cd->next;
        }
-       up(&chrdevs_lock);
+       mutex_unlock(&chrdevs_lock);
        return cd;
 }
 
index d575452..40c4fc9 100644 (file)
@@ -251,3 +251,49 @@ struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_bool);
 
+static ssize_t read_file_blob(struct file *file, char __user *user_buf,
+                             size_t count, loff_t *ppos)
+{
+       struct debugfs_blob_wrapper *blob = file->private_data;
+       return simple_read_from_buffer(user_buf, count, ppos, blob->data,
+                       blob->size);
+}
+
+static struct file_operations fops_blob = {
+       .read =         read_file_blob,
+       .open =         default_open,
+};
+
+/**
+ * debugfs_create_blob - create a file in the debugfs filesystem that is
+ * used to read and write a binary blob.
+ *
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this paramater is NULL, then the
+ *          file will be created in the root of the debugfs filesystem.
+ * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer
+ *        to the blob data and the size of the data.
+ *
+ * This function creates a file in debugfs with the given name that exports
+ * @blob->data as a binary blob. If the @mode variable is so set it can be
+ * read from. Writing is not supported.
+ *
+ * This function will return a pointer to a dentry if it succeeds.  This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.)  If an error occurs, NULL will be returned.
+ *
+ * If debugfs is not enabled in the kernel, the value -ENODEV will be
+ * returned.  It is not wise to check for this value, but rather, check for
+ * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+                                  struct dentry *parent,
+                                  struct debugfs_blob_wrapper *blob)
+{
+       return debugfs_create_file(name, mode, parent, blob, &fops_blob);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_blob);
index 49bd219..9ee9568 100644 (file)
@@ -50,6 +50,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
        return sd;
 }
 
+/**
+ *
+ * Return -EEXIST if there is already a sysfs element with the same name for
+ * the same parent.
+ *
+ * called with parent inode's i_mutex held
+ */
+int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
+                         const unsigned char *new)
+{
+       struct sysfs_dirent * sd;
+
+       list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+               if (sd->s_element) {
+                       const unsigned char *existing = sysfs_get_name(sd);
+                       if (strcmp(existing, new))
+                               continue;
+                       else
+                               return -EEXIST;
+               }
+       }
+
+       return 0;
+}
+
+
 int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
                        void * element, umode_t mode, int type)
 {
@@ -102,7 +128,11 @@ static int create_dir(struct kobject * k, struct dentry * p,
        mutex_lock(&p->d_inode->i_mutex);
        *d = lookup_one_len(n, p, strlen(n));
        if (!IS_ERR(*d)) {
-               error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR);
+               if (sysfs_dirent_exist(p->d_fsdata, n))
+                       error = -EEXIST;
+               else
+                       error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
+                                                               SYSFS_DIR);
                if (!error) {
                        error = sysfs_create(*d, mode, init_dir);
                        if (!error) {
@@ -302,6 +332,7 @@ void sysfs_remove_dir(struct kobject * kobj)
         * Drop reference from dget() on entrance.
         */
        dput(dentry);
+       kobj->dentry = NULL;
 }
 
 int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
@@ -479,7 +510,3 @@ struct file_operations sysfs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = sysfs_readdir,
 };
-
-EXPORT_SYMBOL_GPL(sysfs_create_dir);
-EXPORT_SYMBOL_GPL(sysfs_remove_dir);
-EXPORT_SYMBOL_GPL(sysfs_rename_dir);
index d0e3d84..5e83e72 100644 (file)
@@ -301,9 +301,8 @@ static int check_perm(struct inode * inode, struct file * file)
        /* No error? Great, allocate a buffer for the file, and store it
         * it in file->private_data for easy access.
         */
-       buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);
+       buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
        if (buffer) {
-               memset(buffer,0,sizeof(struct sysfs_buffer));
                init_MUTEX(&buffer->sem);
                buffer->needs_read_fill = 1;
                buffer->ops = ops;
@@ -362,10 +361,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
 {
        struct sysfs_dirent * parent_sd = dir->d_fsdata;
        umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
-       int error = 0;
+       int error = -EEXIST;
 
        mutex_lock(&dir->d_inode->i_mutex);
-       error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
+       if (!sysfs_dirent_exist(parent_sd, attr->name))
+               error = sysfs_make_dirent(parent_sd, NULL, (void *)attr,
+                                         mode, type);
        mutex_unlock(&dir->d_inode->i_mutex);
 
        return error;
index 689f7bc..4c29ac4 100644 (file)
@@ -54,11 +54,10 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 
        if (!sd_iattr) {
                /* setting attributes for the first time, allocate now */
-               sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
+               sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
                if (!sd_iattr)
                        return -ENOMEM;
                /* assign default attributes */
-               memset(sd_iattr, 0, sizeof(struct iattr));
                sd_iattr->ia_mode = sd->s_mode;
                sd_iattr->ia_uid = 0;
                sd_iattr->ia_gid = 0;
@@ -227,12 +226,16 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
 void sysfs_hash_and_remove(struct dentry * dir, const char * name)
 {
        struct sysfs_dirent * sd;
-       struct sysfs_dirent * parent_sd = dir->d_fsdata;
+       struct sysfs_dirent * parent_sd;
+
+       if (!dir)
+               return;
 
        if (dir->d_inode == NULL)
                /* no inode means this hasn't been made visible yet */
                return;
 
+       parent_sd = dir->d_fsdata;
        mutex_lock(&dir->d_inode->i_mutex);
        list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
                if (!sd->s_element)
index e38d633..d2eac3c 100644 (file)
@@ -66,6 +66,7 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj
        if (!error)
                return 0;
 
+       kobject_put(target);
        kfree(sl->link_name);
 exit2:
        kfree(sl);
@@ -82,12 +83,13 @@ exit1:
 int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)
 {
        struct dentry * dentry = kobj->dentry;
-       int error = 0;
+       int error = -EEXIST;
 
        BUG_ON(!kobj || !kobj->dentry || !name);
 
        mutex_lock(&dentry->d_inode->i_mutex);
-       error = sysfs_add_link(dentry, name, target);
+       if (!sysfs_dirent_exist(dentry->d_fsdata, name))
+               error = sysfs_add_link(dentry, name, target);
        mutex_unlock(&dentry->d_inode->i_mutex);
        return error;
 }
index 3f8953e..cf11d5b 100644 (file)
@@ -5,6 +5,7 @@ extern kmem_cache_t *sysfs_dir_cachep;
 extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
 extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
 
+extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);
 extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
                                umode_t, int);
 
index 7772432..60b5105 100644 (file)
@@ -27,7 +27,7 @@ extern void enable_irq(unsigned int);
 
 /*
  * These correspond with the SA_TRIGGER_* defines, and therefore the
- * IRQRESOURCE_IRQ_* defines.
+ * IORESOURCE_IRQ_* defines.
  */
 #define __IRQT_RISEDGE (1 << 0)
 #define __IRQT_FALEDGE (1 << 1)
index 35de20c..9d11550 100644 (file)
                VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;               \
        }                                                               \
                                                                        \
+       /* Kernel symbol table: GPL-future-only symbols */              \
+       __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
+               VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;       \
+               *(__ksymtab_gpl_future)                                 \
+               VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;        \
+       }                                                               \
+                                                                       \
        /* Kernel symbol table: Normal symbols */                       \
        __kcrctab         : AT(ADDR(__kcrctab) - LOAD_OFFSET) {         \
                VMLINUX_SYMBOL(__start___kcrctab) = .;                  \
                VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .;               \
        }                                                               \
                                                                        \
+       /* Kernel symbol table: GPL-future-only symbols */              \
+       __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
+               VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .;       \
+               *(__kcrctab_gpl_future)                                 \
+               VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .;        \
+       }                                                               \
+                                                                       \
        /* Kernel symbol table: strings */                              \
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {        \
                *(__ksymtab_strings)                                    \
index 584f812..aefc02f 100644 (file)
@@ -39,6 +39,24 @@ static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
 }
 #define __arch__swab32(x)      ___arch__swab32(x)
 
+#ifdef CONFIG_CPU_MIPS64_R2
+
+static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x)
+{
+       __asm__(
+       "       dsbh    %0, %1                  \n"
+       "       dshd    %0, %0                  \n"
+       "       drotr   %0, %0, 32              \n"
+       : "=r" (x)
+       : "r" (x));
+
+       return x;
+}
+
+#define __arch__swab64(x)      ___arch__swab64(x)
+
+#endif /* CONFIG_CPU_MIPS64_R2 */
+
 #endif /* CONFIG_CPU_MIPSR2 */
 
 #if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
index 35d2604..0012bd8 100644 (file)
@@ -128,17 +128,17 @@ typedef u32               compat_sigset_word;
  */
 typedef u32            compat_uptr_t;
 
-static inline void *compat_ptr(compat_uptr_t uptr)
+static inline void __user *compat_ptr(compat_uptr_t uptr)
 {
-       return (void *)(long)uptr;
+       return (void __user *)(long)uptr;
 }
 
-static inline void *compat_alloc_user_space(long len)
+static inline void __user *compat_alloc_user_space(long len)
 {
        struct pt_regs *regs = (struct pt_regs *)
                ((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1;
 
-       return (void *) (regs->regs[29] - len);
+       return (void __user *) (regs->regs[29] - len);
 }
 #if defined (__MIPSEL__)
 #define __COMPAT_ENDIAN_SWAP__         1
index ba1d7bb..546a17e 100644 (file)
  * hardware.  An example use would be for flash memory that's used for
  * execute in place.
  */
-# define __raw_ioswabb(x)      (x)
-# define __raw_ioswabw(x)      (x)
-# define __raw_ioswabl(x)      (x)
-# define __raw_ioswabq(x)      (x)
-# define ____raw_ioswabq(x)    (x)
+# define __raw_ioswabb(a,x)    (x)
+# define __raw_ioswabw(a,x)    (x)
+# define __raw_ioswabl(a,x)    (x)
+# define __raw_ioswabq(a,x)    (x)
+# define ____raw_ioswabq(a,x)  (x)
 
-/*
- * Sane hardware offers swapping of PCI/ISA I/O space accesses in hardware;
- * less sane hardware forces software to fiddle with this...
- *
- * Regardless, if the host bus endianness mismatches that of PCI/ISA, then
- * you can't have the numerical value of data and byte addresses within
- * multibyte quantities both preserved at the same time.  Hence two
- * variations of functions: non-prefixed ones that preserve the value
- * and prefixed ones that preserve byte addresses.  The latters are
- * typically used for moving raw data between a peripheral and memory (cf.
- * string I/O functions), hence the "__mem_" prefix.
- */
-#if defined(CONFIG_SWAP_IO_SPACE)
-
-# define ioswabb(x)            (x)
-# define __mem_ioswabb(x)      (x)
-# ifdef CONFIG_SGI_IP22
-/*
- * IP22 seems braindead enough to swap 16bits values in hardware, but
- * not 32bits.  Go figure... Can't tell without documentation.
- */
-#  define ioswabw(x)           (x)
-#  define __mem_ioswabw(x)     le16_to_cpu(x)
-# else
-#  define ioswabw(x)           le16_to_cpu(x)
-#  define __mem_ioswabw(x)     (x)
-# endif
-# define ioswabl(x)            le32_to_cpu(x)
-# define __mem_ioswabl(x)      (x)
-# define ioswabq(x)            le64_to_cpu(x)
-# define __mem_ioswabq(x)      (x)
-
-#else
-
-# define ioswabb(x)            (x)
-# define __mem_ioswabb(x)      (x)
-# define ioswabw(x)            (x)
-# define __mem_ioswabw(x)      cpu_to_le16(x)
-# define ioswabl(x)            (x)
-# define __mem_ioswabl(x)      cpu_to_le32(x)
-# define ioswabq(x)            (x)
-# define __mem_ioswabq(x)      cpu_to_le32(x)
-
-#endif
+/* ioswab[bwlq], __mem_ioswab[bwlq] are defined in mangle-port.h */
 
 #define IO_SPACE_LIMIT 0xffff
 
@@ -346,7 +303,7 @@ static inline void pfx##write##bwlq(type val,                               \
                                                                        \
        __mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem));    \
                                                                        \
-       __val = pfx##ioswab##bwlq(val);                                 \
+       __val = pfx##ioswab##bwlq(__mem, val);                          \
                                                                        \
        if (sizeof(type) != sizeof(u64) || sizeof(u64) == sizeof(long)) \
                *__mem = __val;                                         \
@@ -401,7 +358,7 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem)        \
                BUG();                                                  \
        }                                                               \
                                                                        \
-       return pfx##ioswab##bwlq(__val);                                \
+       return pfx##ioswab##bwlq(__mem, __val);                         \
 }
 
 #define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p, slow)                        \
@@ -411,10 +368,9 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \
        volatile type *__addr;                                          \
        type __val;                                                     \
                                                                        \
-       port = __swizzle_addr_##bwlq(port);                             \
-       __addr = (void *)(mips_io_port_base + port);                    \
+       __addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
                                                                        \
-       __val = pfx##ioswab##bwlq(val);                                 \
+       __val = pfx##ioswab##bwlq(__addr, val);                         \
                                                                        \
        /* Really, we want this to be atomic */                         \
        BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));             \
@@ -428,15 +384,14 @@ static inline type pfx##in##bwlq##p(unsigned long port)                   \
        volatile type *__addr;                                          \
        type __val;                                                     \
                                                                        \
-       port = __swizzle_addr_##bwlq(port);                             \
-       __addr = (void *)(mips_io_port_base + port);                    \
+       __addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
                                                                        \
        BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));             \
                                                                        \
        __val = *__addr;                                                \
        slow;                                                           \
                                                                        \
-       return pfx##ioswab##bwlq(__val);                                \
+       return pfx##ioswab##bwlq(__addr, __val);                        \
 }
 
 #define __BUILD_MEMORY_PFX(bus, bwlq, type)                            \
index 78e1df2..b3c5ecb 100644 (file)
@@ -113,4 +113,6 @@ do {                                                                        \
 # define COBALT_KEY_SELECT     (1 << 7)
 # define COBALT_KEY_MASK       0xfe
 
+#define COBALT_UART            ((volatile unsigned char *) CKSEG1ADDR(0x1c800000))
+
 #endif /* __ASM_COBALT_H */
index 4a98d83..6e1b0c0 100644 (file)
 #define __swizzle_addr_l(port) (port)
 #define __swizzle_addr_q(port) (port)
 
+/*
+ * Sane hardware offers swapping of PCI/ISA I/O space accesses in hardware;
+ * less sane hardware forces software to fiddle with this...
+ *
+ * Regardless, if the host bus endianness mismatches that of PCI/ISA, then
+ * you can't have the numerical value of data and byte addresses within
+ * multibyte quantities both preserved at the same time.  Hence two
+ * variations of functions: non-prefixed ones that preserve the value
+ * and prefixed ones that preserve byte addresses.  The latters are
+ * typically used for moving raw data between a peripheral and memory (cf.
+ * string I/O functions), hence the "__mem_" prefix.
+ */
+#if defined(CONFIG_SWAP_IO_SPACE)
+
+# define ioswabb(a,x)          (x)
+# define __mem_ioswabb(a,x)    (x)
+# define ioswabw(a,x)          le16_to_cpu(x)
+# define __mem_ioswabw(a,x)    (x)
+# define ioswabl(a,x)          le32_to_cpu(x)
+# define __mem_ioswabl(a,x)    (x)
+# define ioswabq(a,x)          le64_to_cpu(x)
+# define __mem_ioswabq(a,x)    (x)
+
+#else
+
+# define ioswabb(a,x)          (x)
+# define __mem_ioswabb(a,x)    (x)
+# define ioswabw(a,x)          (x)
+# define __mem_ioswabw(a,x)    cpu_to_le16(x)
+# define ioswabl(a,x)          (x)
+# define __mem_ioswabl(a,x)    cpu_to_le32(x)
+# define ioswabq(a,x)          (x)
+# define __mem_ioswabq(a,x)    cpu_to_le32(x)
+
+#endif
+
 #endif /* __ASM_MACH_GENERIC_MANGLE_PORT_H */
index f76c448..d615312 100644 (file)
 #define __swizzle_addr_l(port) (port)
 #define __swizzle_addr_q(port) (port)
 
+# define ioswabb(a,x)          (x)
+# define __mem_ioswabb(a,x)    (x)
+# define ioswabw(a,x)          (x)
+# define __mem_ioswabw(a,x)    cpu_to_le16(x)
+# define ioswabl(a,x)          (x)
+# define __mem_ioswabl(a,x)    cpu_to_le32(x)
+# define ioswabq(a,x)          (x)
+# define __mem_ioswabq(a,x)    cpu_to_le32(x)
+
 #endif /* __ASM_MACH_IP27_MANGLE_PORT_H */
index 6e25b52..81320eb 100644 (file)
 #define __swizzle_addr_l(port) (port)
 #define __swizzle_addr_q(port) (port)
 
+# define ioswabb(a,x)          (x)
+# define __mem_ioswabb(a,x)    (x)
+# define ioswabw(a,x)          (x)
+# define __mem_ioswabw(a,x)    cpu_to_le16(x)
+# define ioswabl(a,x)          (x)
+# define __mem_ioswabl(a,x)    cpu_to_le32(x)
+# define ioswabq(a,x)          (x)
+# define __mem_ioswabq(a,x)    cpu_to_le32(x)
+
 #endif /* __ASM_MACH_IP32_MANGLE_PORT_H */
index 9f92aed..e06af6c 100644 (file)
 /* #define cpu_has_prefetch    ? */
 #define cpu_has_mcheck         1
 /* #define cpu_has_ejtag       ? */
+#ifdef CONFIG_CPU_HAS_LLSC
 #define cpu_has_llsc           1
+#else
+#define cpu_has_llsc           0
+#endif
 /* #define cpu_has_vtag_icache ? */
 /* #define cpu_has_dc_aliases  ? */
 /* #define cpu_has_ic_fills_f_dc ? */
index 19cdf76..61cf225 100644 (file)
@@ -33,12 +33,7 @@ extern unsigned long pgd_current[];
        write_c0_context((unsigned long) smp_processor_id() << 25);     \
        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
 #endif
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-#define TLBMISS_HANDLER_SETUP()                                                \
-       write_c0_context((unsigned long) &pgd_current[smp_processor_id()] << 23); \
-       TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
-#endif
-#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
+#ifdef CONFIG_64BIT
 #define TLBMISS_HANDLER_SETUP()                                                \
        write_c0_context((unsigned long) smp_processor_id() << 26);     \
        TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
index 0cff64c..4d6bc45 100644 (file)
@@ -206,7 +206,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot)
        /* fixme */
 #define pte_to_pgoff(_pte) (((_pte).pte_high >> 6) + ((_pte).pte_high & 0x3f))
 #define pgoff_to_pte(off) \
-       ((pte_t){(((off) & 0x3f) + ((off) << 6) + _PAGE_FILE)})
+       ((pte_t){(((off) & 0x3f) + ((off) << 6) + _PAGE_FILE)})
 
 #else
 #define pte_to_pgoff(_pte) \
index 0bcb79a..90c3747 100644 (file)
@@ -303,5 +303,6 @@ __BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
 __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
 /* blast_inv_dcache_range */
 __BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
+__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
 
 #endif /* _ASM_R4KCACHE_H */
index 6fe903e..d8349e4 100644 (file)
@@ -147,16 +147,34 @@ struct k_sigaction {
 
 /* IRIX compatible stack_t  */
 typedef struct sigaltstack {
-       void *ss_sp;
+       void __user *ss_sp;
        size_t ss_size;
        int ss_flags;
 } stack_t;
 
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
+#include <asm/siginfo.h>
 
 #define ptrace_signal_deliver(regs, cookie) do { } while (0)
 
+struct pt_regs;
+extern void do_signal(struct pt_regs *regs);
+extern void do_signal32(struct pt_regs *regs);
+
+extern int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set);
+extern int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set, siginfo_t *info);
+
+extern int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set);
+extern int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set, siginfo_t *info);
+
+extern int setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs,
+        int signr, sigset_t *set, siginfo_t *info);
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_SIGNAL_H */
index d028e28..9709ff7 100644 (file)
@@ -99,7 +99,7 @@ typedef s32 klconf_off_t;
 #define ENABLE_BOARD           0x01
 #define FAILED_BOARD           0x02
 #define DUPLICATE_BOARD        0x04    /* Boards like midplanes/routers which
-                                          are discovered twice. Use one of them */
+                                          are discovered twice. Use one of them */
 #define VISITED_BOARD          0x08    /* Used for compact hub numbering. */
 #define LOCAL_MASTER_IO6       0x10    /* master io6 for that node */
 #define GLOBAL_MASTER_IO6      0x20
index 3a17846..59edb20 100644 (file)
 #include <linux/config.h>
 #include <asm/addrspace.h>
 
-#ifdef CONFIG_BUILD_ELF64
 #define REP_BASE       CAC_BASE
-#else
-#define REP_BASE       CKSEG0
-#endif
 
 #ifdef CONFIG_MAPPED_KERNEL
 
index 80cf6a5..f314da2 100644 (file)
@@ -229,7 +229,7 @@ typedef union hubii_ilcsr_u {
                         icsr_llp_en:    1,     /* LLP enable bit */
                        icsr_rsvd2:      1,     /* reserver */
                         icsr_wrm_reset:         1,     /* Warm reset bit */
-                       icsr_rsvd1:      2,     /* Data ready offset */
+                       icsr_rsvd1:      2,     /* Data ready offset */
                         icsr_null_to:   6;     /* Null timeout   */
 
         } icsr_fields_s;
@@ -274,9 +274,9 @@ typedef union io_perf_sel {
        u64 perf_sel_reg;
        struct {
                u64     perf_rsvd  : 48,
-                       perf_icct  :  8,
-                       perf_ippr1 :  4,
-                       perf_ippr0 :  4;
+                       perf_icct  :  8,
+                       perf_ippr1 :  4,
+                       perf_ippr0 :  4;
        } perf_sel_bits;
 } io_perf_sel_t;
 
@@ -287,8 +287,8 @@ typedef union io_perf_cnt {
        u64     perf_cnt;
        struct {
                u64     perf_rsvd1 : 32,
-                               perf_rsvd2 : 12,
-                               perf_cnt   : 20;
+                       perf_rsvd2 : 12,
+                       perf_cnt   : 20;
        } perf_cnt_bits;
 } io_perf_cnt_t;
 
index a8919dc..2acf3e8 100644 (file)
                addu    k1, k0
                LONG_L  k1, %lo(kernelsp)(k1)
 #endif
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-               MFC0    k1, CP0_CONTEXT
-               dsra    k1, 23
-               lui     k0, %hi(pgd_current)
-               addiu   k0, %lo(pgd_current)
-               dsubu   k1, k0
-               lui     k0, %hi(kernelsp)
-               daddu   k1, k0
-               LONG_L  k1, %lo(kernelsp)(k1)
-#endif
-#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
+#ifdef CONFIG_64BIT
                MFC0    k1, CP0_CONTEXT
                lui     k0, %highest(kernelsp)
                dsrl    k1, 23
                mfc0    \temp, CP0_CONTEXT
                srl     \temp, 23
 #endif
-#if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
-               lw      \temp, TI_CPU(gp)
-               dsll    \temp, 3
-#endif
-#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
+#ifdef CONFIG_64BIT
                MFC0    \temp, CP0_CONTEXT
                dsrl    \temp, 23
 #endif
                .endm
 #else
                .macro  get_saved_sp    /* Uniprocessor variation */
-#if defined(CONFIG_64BIT) && defined(CONFIG_BUILD_ELF64)
+#ifdef CONFIG_64BIT
                lui     k1, %highest(kernelsp)
                daddiu  k1, %higher(kernelsp)
                dsll    k1, k1, 16
index ddae9ba..4097fac 100644 (file)
@@ -286,10 +286,10 @@ extern void __xchg_called_with_bad_pointer(void);
 static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
 {
        switch (size) {
-               case 4:
-                       return __xchg_u32(ptr, x);
-               case 8:
-                       return __xchg_u64(ptr, x);
+       case 4:
+               return __xchg_u32(ptr, x);
+       case 8:
+               return __xchg_u64(ptr, x);
        }
        __xchg_called_with_bad_pointer();
        return x;
index fa193f8..f8d97da 100644 (file)
@@ -31,7 +31,7 @@ struct thread_info {
        int                     preempt_count;  /* 0 => preemptable, <0 => BUG */
 
        mm_segment_t            addr_limit;     /* thread address space:
-                                                  0-0xBFFFFFFF for user-thead
+                                                  0-0xBFFFFFFF for user-thead
                                                   0-0xFFFFFFFF for kernel-thread
                                                */
        struct restart_block    restart_block;
index 09575b6..4e0ce3a 100644 (file)
@@ -47,7 +47,7 @@
 #define SO_TIMESTAMP           0x001d
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 
-#define SO_PEERSEC             0x100e
+#define SO_PEERSEC             0x001e
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
index 6b8d73d..9cf64b1 100644 (file)
@@ -54,6 +54,7 @@
 #define CNTL_LCDBPP4           (2 << 1)
 #define CNTL_LCDBPP8           (3 << 1)
 #define CNTL_LCDBPP16          (4 << 1)
+#define CNTL_LCDBPP16_565      (6 << 1)
 #define CNTL_LCDBPP24          (5 << 1)
 #define CNTL_LCDBW             (1 << 4)
 #define CNTL_LCDTFT            (1 << 5)
@@ -209,7 +210,16 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
                val |= CNTL_LCDBPP8;
                break;
        case 16:
-               val |= CNTL_LCDBPP16;
+               /*
+                * PL110 cannot choose between 5551 and 565 modes in
+                * its control register
+                */
+               if ((fb->dev->periphid & 0x000fffff) == 0x00041110)
+                       val |= CNTL_LCDBPP16;
+               else if (fb->fb.var.green.length == 5)
+                       val |= CNTL_LCDBPP16;
+               else
+                       val |= CNTL_LCDBPP16_565;
                break;
        case 32:
                val |= CNTL_LCDBPP24;
index 94f77cc..b02a16c 100644 (file)
@@ -267,6 +267,16 @@ struct ata_taskfile {
          ((u64) (id)[(n) + 1] << 16) | \
          ((u64) (id)[(n) + 0]) )
 
+static inline unsigned int ata_id_major_version(const u16 *id)
+{
+       unsigned int mver;
+
+       for (mver = 14; mver >= 1; mver--)
+               if (id[ATA_ID_MAJOR_VER] & (1 << mver))
+                       break;
+       return mver;
+}
+
 static inline int ata_id_current_chs_valid(const u16 *id)
 {
        /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command 
@@ -302,4 +312,16 @@ static inline int ata_ok(u8 status)
                        == ATA_DRDY);
 }
 
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+       /* check the ending block number */
+       return ((block + n_block - 1) < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+       /* check the ending block number */
+       return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
 #endif /* __LINUX_ATA_H__ */
index 0ed1d48..d612b89 100644 (file)
@@ -32,7 +32,7 @@ struct cpu {
 };
 
 extern int register_cpu(struct cpu *, int, struct node *);
-extern struct sys_device *get_cpu_sysdev(int cpu);
+extern struct sys_device *get_cpu_sysdev(unsigned cpu);
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *, struct node *);
 #endif
index 088529f..676333b 100644 (file)
@@ -18,7 +18,7 @@
  * @dccph_seq - sequence number high or low order 24 bits, depends on dccph_x
  */
 struct dccp_hdr {
-       __u16   dccph_sport,
+       __be16  dccph_sport,
                dccph_dport;
        __u8    dccph_doff;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
@@ -32,18 +32,18 @@ struct dccp_hdr {
 #endif
        __u16   dccph_checksum;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
-       __u32   dccph_x:1,
+       __u   dccph_x:1,
                dccph_type:4,
-               dccph_reserved:3,
-               dccph_seq:24;
+               dccph_reserved:3;
 #elif defined(__BIG_ENDIAN_BITFIELD)
-       __u32   dccph_reserved:3,
+       __u   dccph_reserved:3,
                dccph_type:4,
-               dccph_x:1,
-               dccph_seq:24;
+               dccph_x:1;
 #else
 #error  "Adjust your <asm/byteorder.h> defines"
 #endif
+       __u8    dccph_seq2;
+       __be16  dccph_seq;
 };
 
 /**
@@ -52,7 +52,7 @@ struct dccp_hdr {
  * @dccph_seq_low - low 24 bits of a 48 bit seq packet
  */
 struct dccp_hdr_ext {
-       __u32   dccph_seq_low;
+       __be32  dccph_seq_low;
 };
 
 /**
@@ -62,7 +62,7 @@ struct dccp_hdr_ext {
  * @dccph_req_options - list of options (must be a multiple of 32 bits
  */
 struct dccp_hdr_request {
-       __u32   dccph_req_service;
+       __be32  dccph_req_service;
 };
 /**
  * struct dccp_hdr_ack_bits - acknowledgment bits common to most packets
@@ -71,9 +71,9 @@ struct dccp_hdr_request {
  * @dccph_resp_ack_nr_low - 48 bit ack number low order bits, contains GSR
  */
 struct dccp_hdr_ack_bits {
-       __u32   dccph_reserved1:8,
-               dccph_ack_nr_high:24;
-       __u32   dccph_ack_nr_low;
+       __be16  dccph_reserved1;
+       __be16  dccph_ack_nr_high;
+       __be32  dccph_ack_nr_low;
 };
 /**
  * struct dccp_hdr_response - Conection initiation response header
@@ -85,7 +85,7 @@ struct dccp_hdr_ack_bits {
  */
 struct dccp_hdr_response {
        struct dccp_hdr_ack_bits        dccph_resp_ack;
-       __u32                           dccph_resp_service;
+       __be32                          dccph_resp_service;
 };
 
 /**
@@ -154,6 +154,10 @@ enum {
        DCCPO_MANDATORY = 1,
        DCCPO_MIN_RESERVED = 3,
        DCCPO_MAX_RESERVED = 31,
+       DCCPO_CHANGE_L = 32,
+       DCCPO_CONFIRM_L = 33,
+       DCCPO_CHANGE_R = 34,
+       DCCPO_CONFIRM_R = 35,
        DCCPO_NDP_COUNT = 37,
        DCCPO_ACK_VECTOR_0 = 38,
        DCCPO_ACK_VECTOR_1 = 39,
@@ -168,7 +172,9 @@ enum {
 /* DCCP features */
 enum {
        DCCPF_RESERVED = 0,
+       DCCPF_CCID = 1,
        DCCPF_SEQUENCE_WINDOW = 3,
+       DCCPF_ACK_RATIO = 5,
        DCCPF_SEND_ACK_VECTOR = 6,
        DCCPF_SEND_NDP_COUNT = 7,
        /* 10-127 reserved */
@@ -176,9 +182,18 @@ enum {
        DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
+/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
+struct dccp_so_feat {
+       __u8 dccpsf_feat;
+       __u8 *dccpsf_val;
+       __u8 dccpsf_len;
+};
+
 /* DCCP socket options */
 #define DCCP_SOCKOPT_PACKET_SIZE       1
 #define DCCP_SOCKOPT_SERVICE           2
+#define DCCP_SOCKOPT_CHANGE_L          3
+#define DCCP_SOCKOPT_CHANGE_R          4
 #define DCCP_SOCKOPT_CCID_RX_INFO      128
 #define DCCP_SOCKOPT_CCID_TX_INFO      192
 
@@ -254,16 +269,12 @@ static inline unsigned int dccp_basic_hdr_len(const struct sk_buff *skb)
 static inline __u64 dccp_hdr_seq(const struct sk_buff *skb)
 {
        const struct dccp_hdr *dh = dccp_hdr(skb);
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       __u64 seq_nr = ntohl(dh->dccph_seq << 8);
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       __u64 seq_nr = ntohl(dh->dccph_seq);
-#else
-#error  "Adjust your <asm/byteorder.h> defines"
-#endif
+       __u64 seq_nr =  ntohs(dh->dccph_seq);
 
        if (dh->dccph_x != 0)
                seq_nr = (seq_nr << 32) + ntohl(dccp_hdrx(skb)->dccph_seq_low);
+       else
+               seq_nr += (u32)dh->dccph_seq2 << 16;
 
        return seq_nr;
 }
@@ -281,13 +292,7 @@ static inline struct dccp_hdr_ack_bits *dccp_hdr_ack_bits(const struct sk_buff *
 static inline u64 dccp_hdr_ack_seq(const struct sk_buff *skb)
 {
        const struct dccp_hdr_ack_bits *dhack = dccp_hdr_ack_bits(skb);
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       return (((u64)ntohl(dhack->dccph_ack_nr_high << 8)) << 32) + ntohl(dhack->dccph_ack_nr_low);
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       return (((u64)ntohl(dhack->dccph_ack_nr_high)) << 32) + ntohl(dhack->dccph_ack_nr_low);
-#else
-#error  "Adjust your <asm/byteorder.h> defines"
-#endif
+       return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) + ntohl(dhack->dccph_ack_nr_low);
 }
 
 static inline struct dccp_hdr_response *dccp_hdr_response(struct sk_buff *skb)
@@ -314,38 +319,60 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 
 /* initial values for each feature */
 #define DCCPF_INITIAL_SEQUENCE_WINDOW          100
-/* FIXME: for now we're using CCID 3 (TFRC) */
-#define DCCPF_INITIAL_CCID                     3
-#define DCCPF_INITIAL_SEND_ACK_VECTOR          0
+#define DCCPF_INITIAL_ACK_RATIO                        2
+#define DCCPF_INITIAL_CCID                     2
+#define DCCPF_INITIAL_SEND_ACK_VECTOR          1
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT           1
 
 #define DCCP_NDP_LIMIT 0xFFFFFF
 
 /**
-  * struct dccp_options - option values for a DCCP connection
-  *    @dccpo_sequence_window - Sequence Window Feature (section 7.5.2)
-  *    @dccpo_ccid - Congestion Control Id (CCID) (section 10)
-  *    @dccpo_send_ack_vector - Send Ack Vector Feature (section 11.5)
-  *    @dccpo_send_ndp_count - Send NDP Count Feature (7.7.2)
+  * struct dccp_minisock - Minimal DCCP connection representation
+  *
+  * Will be used to pass the state from dccp_request_sock to dccp_sock.
+  *
+  * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
+  * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
+  * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
+  * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   */
-struct dccp_options {
-       __u64   dccpo_sequence_window;
-       __u8    dccpo_rx_ccid;
-       __u8    dccpo_tx_ccid;
-       __u8    dccpo_send_ack_vector;
-       __u8    dccpo_send_ndp_count;
+struct dccp_minisock {
+       __u64                   dccpms_sequence_window;
+       __u8                    dccpms_rx_ccid;
+       __u8                    dccpms_tx_ccid;
+       __u8                    dccpms_send_ack_vector;
+       __u8                    dccpms_send_ndp_count;
+       __u8                    dccpms_ack_ratio;
+       struct list_head        dccpms_pending;
+       struct list_head        dccpms_conf;
+};
+
+struct dccp_opt_conf {
+       __u8                    *dccpoc_val;
+       __u8                    dccpoc_len;
+};
+
+struct dccp_opt_pend {
+       struct list_head        dccpop_node;
+       __u8                    dccpop_type;
+       __u8                    dccpop_feat;
+       __u8                    *dccpop_val;
+       __u8                    dccpop_len;
+       int                     dccpop_conf;
+       struct dccp_opt_conf    *dccpop_sc;
 };
 
-extern void __dccp_options_init(struct dccp_options *dccpo);
-extern void dccp_options_init(struct dccp_options *dccpo);
+extern void __dccp_minisock_init(struct dccp_minisock *dmsk);
+extern void dccp_minisock_init(struct dccp_minisock *dmsk);
+
 extern int dccp_parse_options(struct sock *sk, struct sk_buff *skb);
 
 struct dccp_request_sock {
        struct inet_request_sock dreq_inet_rsk;
        __u64                    dreq_iss;
        __u64                    dreq_isr;
-       __u32                    dreq_service;
+       __be32                   dreq_service;
 };
 
 static inline struct dccp_request_sock *dccp_rsk(const struct request_sock *req)
@@ -373,13 +400,13 @@ enum dccp_role {
 
 struct dccp_service_list {
        __u32   dccpsl_nr;
-       __u32   dccpsl_list[0];
+       __be32  dccpsl_list[0];
 };
 
 #define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1)
 
 static inline int dccp_list_has_service(const struct dccp_service_list *sl,
-                                       const u32 service)
+                                       const __be32 service)
 {
        if (likely(sl != NULL)) {
                u32 i = sl->dccpsl_nr;
@@ -425,17 +452,17 @@ struct dccp_sock {
        __u64                           dccps_gss;
        __u64                           dccps_gsr;
        __u64                           dccps_gar;
-       __u32                           dccps_service;
+       __be32                          dccps_service;
        struct dccp_service_list        *dccps_service_list;
        struct timeval                  dccps_timestamp_time;
        __u32                           dccps_timestamp_echo;
        __u32                           dccps_packet_size;
+       __u16                           dccps_l_ack_ratio;
+       __u16                           dccps_r_ack_ratio;
        unsigned long                   dccps_ndp_count;
        __u32                           dccps_mss_cache;
-       struct dccp_options             dccps_options;
+       struct dccp_minisock            dccps_minisock;
        struct dccp_ackvec              *dccps_hc_rx_ackvec;
-       void                            *dccps_hc_rx_ccid_private;
-       void                            *dccps_hc_tx_ccid_private;
        struct ccid                     *dccps_hc_rx_ccid;
        struct ccid                     *dccps_hc_tx_ccid;
        struct dccp_options_received    dccps_options_received;
@@ -450,6 +477,11 @@ static inline struct dccp_sock *dccp_sk(const struct sock *sk)
        return (struct dccp_sock *)sk;
 }
 
+static inline struct dccp_minisock *dccp_msk(const struct sock *sk)
+{
+       return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
+}
+
 static inline int dccp_service_not_initialized(const struct sock *sk)
 {
        return dccp_sk(sk)->dccps_service == DCCP_SERVICE_INVALID_VALUE;
index a5fa6a6..4b0428e 100644 (file)
 
 struct file_operations;
 
+struct debugfs_blob_wrapper {
+       void *data;
+       unsigned long size;
+};
+
 #if defined(CONFIG_DEBUG_FS)
 struct dentry *debugfs_create_file(const char *name, mode_t mode,
                                   struct dentry *parent, void *data,
@@ -39,6 +44,9 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 struct dentry *debugfs_create_bool(const char *name, mode_t mode,
                                  struct dentry *parent, u32 *value);
 
+struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+                                 struct dentry *parent,
+                                 struct debugfs_blob_wrapper *blob);
 #else
 
 #include <linux/err.h>
@@ -94,6 +102,13 @@ static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
        return ERR_PTR(-ENODEV);
 }
 
+static inline struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+                                 struct dentry *parent,
+                                 struct debugfs_blob_wrapper *blob)
+{
+       return ERR_PTR(-ENODEV);
+}
+
 #endif
 
 #endif
index 58df18d..5b595fd 100644 (file)
@@ -424,6 +424,8 @@ extern void firmware_unregister(struct subsystem *);
        dev_printk(KERN_INFO , dev , format , ## arg)
 #define dev_warn(dev, format, arg...)          \
        dev_printk(KERN_WARNING , dev , format , ## arg)
+#define dev_notice(dev, format, arg...)                \
+       dev_printk(KERN_NOTICE , dev , format , ## arg)
 
 /* Create alias, so I can be autoloaded. */
 #define MODULE_ALIAS_CHARDEV(major,minor) \
index 782cae4..10b6a6f 100644 (file)
 
 struct dn_naddr 
 {
-       unsigned short          a_len;
-       unsigned char a_addr[DN_MAXADDL];
+       __le16          a_len;
+       __u8 a_addr[DN_MAXADDL]; /* Two bytes little endian */
 };
 
 struct sockaddr_dn
 {
-       unsigned short          sdn_family;
-       unsigned char           sdn_flags;
-       unsigned char           sdn_objnum;
-       unsigned short          sdn_objnamel;
-       unsigned char           sdn_objname[DN_MAXOBJL];
+       __u16           sdn_family;
+       __u8            sdn_flags;
+       __u8            sdn_objnum;
+       __le16          sdn_objnamel;
+       __u8            sdn_objname[DN_MAXOBJL];
        struct   dn_naddr       sdn_add;
 };
 #define sdn_nodeaddrl   sdn_add.a_len   /* Node address length  */
@@ -93,38 +93,38 @@ struct sockaddr_dn
  * DECnet set/get DSO_CONDATA, DSO_DISDATA (optional data) structure
  */
 struct optdata_dn {
-        unsigned short  opt_status;     /* Extended status return */
+        __le16  opt_status;     /* Extended status return */
 #define opt_sts opt_status
-        unsigned short  opt_optl;       /* Length of user data    */
-        unsigned char   opt_data[16];   /* User data              */
+        __le16  opt_optl;       /* Length of user data    */
+        __u8   opt_data[16];   /* User data              */
 };
 
 struct accessdata_dn
 {
-       unsigned char           acc_accl;
-       unsigned char           acc_acc[DN_MAXACCL];
-       unsigned char           acc_passl;
-       unsigned char           acc_pass[DN_MAXACCL];
-       unsigned char           acc_userl;
-       unsigned char           acc_user[DN_MAXACCL];
+       __u8            acc_accl;
+       __u8            acc_acc[DN_MAXACCL];
+       __u8            acc_passl;
+       __u8            acc_pass[DN_MAXACCL];
+       __u8            acc_userl;
+       __u8            acc_user[DN_MAXACCL];
 };
 
 /*
  * DECnet logical link information structure
  */
 struct linkinfo_dn {
-        unsigned short  idn_segsize;    /* Segment size for link */
-        unsigned char   idn_linkstate;  /* Logical link state    */
+        __le16  idn_segsize;    /* Segment size for link */
+        __u8   idn_linkstate;  /* Logical link state    */
 };
 
 /*
  * Ethernet address format (for DECnet)
  */
 union etheraddress {
-        unsigned char dne_addr[6];             /* Full ethernet address */
+        __u8 dne_addr[6];             /* Full ethernet address */
   struct {
-                unsigned char dne_hiord[4];    /* DECnet HIORD prefix   */
-                unsigned char dne_nodeaddr[2]; /* DECnet node address   */
+                __u8 dne_hiord[4];    /* DECnet HIORD prefix   */
+                __u8 dne_nodeaddr[2]; /* DECnet node address   */
   } dne_remote;
 };
 
@@ -133,7 +133,7 @@ union etheraddress {
  * DECnet physical socket address format
  */
 struct dn_addr {
-        unsigned short dna_family;      /* AF_DECnet               */
+        __le16 dna_family;      /* AF_DECnet               */
         union etheraddress dna_netaddr; /* DECnet ethernet address */
 };
 
index 2b87970..0874a67 100644 (file)
@@ -121,4 +121,17 @@ typedef uint16_t audio_attributes_t;
 #define AUDIO_SET_ATTRIBUTES       _IOW('o', 17, audio_attributes_t)
 #define AUDIO_SET_KARAOKE          _IOW('o', 18, audio_karaoke_t)
 
+/**
+ * AUDIO_GET_PTS
+ *
+ * Read the 33 bit presentation time stamp as defined
+ * in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+ *
+ * The PTS should belong to the currently played
+ * frame if possible, but may also be a value close to it
+ * like the PTS of the last decoded frame or the last PTS
+ * extracted by the PES parser.
+ */
+#define AUDIO_GET_PTS              _IOR('o', 19, __u64)
+
 #endif /* _DVBAUDIO_H_ */
index b81e58b..faebfda 100644 (file)
@@ -200,4 +200,17 @@ typedef uint16_t video_attributes_t;
 #define VIDEO_GET_SIZE             _IOR('o', 55, video_size_t)
 #define VIDEO_GET_FRAME_RATE       _IOR('o', 56, unsigned int)
 
+/**
+ * VIDEO_GET_PTS
+ *
+ * Read the 33 bit presentation time stamp as defined
+ * in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+ *
+ * The PTS should belong to the currently played
+ * frame if possible, but may also be a value close to it
+ * like the PTS of the last decoded frame or the last PTS
+ * extracted by the PES parser.
+ */
+#define VIDEO_GET_PTS              _IOR('o', 57, __u64)
+
 #endif /*_DVBVIDEO_H_*/
index a9f1cfd..a3a0e07 100644 (file)
@@ -83,5 +83,32 @@ struct fsl_i2c_platform_data {
 #define FSL_I2C_DEV_SEPARATE_DFSRR     0x00000001
 #define FSL_I2C_DEV_CLOCK_5200         0x00000002
 
+
+enum fsl_usb2_operating_modes {
+       FSL_USB2_MPH_HOST,
+       FSL_USB2_DR_HOST,
+       FSL_USB2_DR_DEVICE,
+       FSL_USB2_DR_OTG,
+};
+
+enum fsl_usb2_phy_modes {
+       FSL_USB2_PHY_NONE,
+       FSL_USB2_PHY_ULPI,
+       FSL_USB2_PHY_UTMI,
+       FSL_USB2_PHY_UTMI_WIDE,
+       FSL_USB2_PHY_SERIAL,
+};
+
+struct fsl_usb2_platform_data {
+       /* board specific information */
+       enum fsl_usb2_operating_modes operating_mode;
+       enum fsl_usb2_phy_modes phy_mode;
+       unsigned int port_enables;
+};
+
+/* Flags in fsl_usb2_mph_platform_data */
+#define FSL_USB2_PORT0_ENABLED 0x00000001
+#define FSL_USB2_PORT1_ENABLED 0x00000002
+
 #endif                         /* _FSL_DEVICE_H_ */
 #endif                         /* __KERNEL__ */
index 0cf6c8b..c771a7d 100644 (file)
@@ -40,14 +40,16 @@ struct icmp6hdr {
                 struct icmpv6_nd_ra {
                        __u8            hop_limit;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
-                       __u8            reserved:6,
+                       __u8            reserved:4,
+                                       router_pref:2,
                                        other:1,
                                        managed:1;
 
 #elif defined(__BIG_ENDIAN_BITFIELD)
                        __u8            managed:1,
                                        other:1,
-                                       reserved:6;
+                                       router_pref:2,
+                                       reserved:4;
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
@@ -70,8 +72,13 @@ struct icmp6hdr {
 #define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
 #define icmp6_addrconf_other   icmp6_dataun.u_nd_ra.other
 #define icmp6_rt_lifetime      icmp6_dataun.u_nd_ra.rt_lifetime
+#define icmp6_router_pref      icmp6_dataun.u_nd_ra.router_pref
 };
 
+#define ICMPV6_ROUTER_PREF_LOW         0x3
+#define ICMPV6_ROUTER_PREF_MEDIUM      0x0
+#define ICMPV6_ROUTER_PREF_HIGH                0x1
+#define ICMPV6_ROUTER_PREF_INVALID     0x2
 
 #define ICMPV6_DEST_UNREACH            1
 #define ICMPV6_PKT_TOOBIG              2
index 12c6f6d..374e20a 100644 (file)
@@ -33,7 +33,7 @@
 #define        IFF_LOOPBACK    0x8             /* is a loopback net            */
 #define        IFF_POINTOPOINT 0x10            /* interface is has p-p link    */
 #define        IFF_NOTRAILERS  0x20            /* avoid use of trailers        */
-#define        IFF_RUNNING     0x40            /* interface running and carrier ok */
+#define        IFF_RUNNING     0x40            /* interface RFC2863 OPER_UP    */
 #define        IFF_NOARP       0x80            /* no ARP protocol              */
 #define        IFF_PROMISC     0x100           /* receive all packets          */
 #define        IFF_ALLMULTI    0x200           /* receive all multicast packets*/
 
 #define IFF_MULTICAST  0x1000          /* Supports multicast           */
 
-#define IFF_VOLATILE   (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_MASTER|IFF_SLAVE|IFF_RUNNING)
-
 #define IFF_PORTSEL    0x2000          /* can set media type           */
 #define IFF_AUTOMEDIA  0x4000          /* auto media select active     */
 #define IFF_DYNAMIC    0x8000          /* dialup device with changing addresses*/
 
+#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
+#define IFF_DORMANT    0x20000         /* driver signals dormant       */
+
+#define IFF_VOLATILE   (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|\
+               IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+
 /* Private (from user) interface flags (netdevice->priv_flags). */
 #define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
 #define IFF_EBRIDGE    0x2             /* Ethernet bridging device.    */
 #define IF_PROTO_FR_ETH_PVC 0x200B
 #define IF_PROTO_RAW    0x200C          /* RAW Socket                   */
 
+/* RFC 2863 operational status */
+enum {
+       IF_OPER_UNKNOWN,
+       IF_OPER_NOTPRESENT,
+       IF_OPER_DOWN,
+       IF_OPER_LOWERLAYERDOWN,
+       IF_OPER_TESTING,
+       IF_OPER_DORMANT,
+       IF_OPER_UP,
+};
+
+/* link modes */
+enum {
+       IF_LINK_MODE_DEFAULT,
+       IF_LINK_MODE_DORMANT,   /* limit upward transition to dormant */
+};
 
 /*
  *     Device mapping structure. I'd just gone off and designed a 
index ba35538..94f557f 100644 (file)
@@ -72,6 +72,7 @@ struct in_addr {
 #define IP_FREEBIND    15
 #define IP_IPSEC_POLICY        16
 #define IP_XFRM_POLICY 17
+#define IP_PASSSEC     18
 
 /* BSD compatibility */
 #define IP_RECVRETOPTS IP_RETOPTS
index fd7af86..92297ff 100644 (file)
@@ -25,6 +25,7 @@ struct ipv4_devconf
        int     arp_filter;
        int     arp_announce;
        int     arp_ignore;
+       int     arp_accept;
        int     medium_id;
        int     no_xfrm;
        int     no_policy;
index 9c8f4c9..1263d8c 100644 (file)
@@ -145,6 +145,15 @@ struct ipv6_devconf {
        __s32           max_desync_factor;
 #endif
        __s32           max_addresses;
+       __s32           accept_ra_defrtr;
+       __s32           accept_ra_pinfo;
+#ifdef CONFIG_IPV6_ROUTER_PREF
+       __s32           accept_ra_rtr_pref;
+       __s32           rtr_probe_interval;
+#ifdef CONFIG_IPV6_ROUTE_INFO
+       __s32           accept_ra_rt_info_max_plen;
+#endif
+#endif
        void            *sysctl;
 };
 
@@ -167,6 +176,11 @@ enum {
        DEVCONF_MAX_DESYNC_FACTOR,
        DEVCONF_MAX_ADDRESSES,
        DEVCONF_FORCE_MLD_VERSION,
+       DEVCONF_ACCEPT_RA_DEFRTR,
+       DEVCONF_ACCEPT_RA_PINFO,
+       DEVCONF_ACCEPT_RA_RTR_PREF,
+       DEVCONF_RTR_PROBE_INTERVAL,
+       DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
        DEVCONF_MAX
 };
 
index d7c41d1..b323ff5 100644 (file)
 #define RTF_NONEXTHOP  0x00200000      /* route with no nexthop        */
 #define RTF_EXPIRES    0x00400000
 
+#define RTF_ROUTEINFO  0x00800000      /* route information - RA       */
+
 #define RTF_CACHE      0x01000000      /* cache entry                  */
 #define RTF_FLOW       0x02000000      /* flow significant route       */
 #define RTF_POLICY     0x04000000      /* policy route                 */
 
+#define RTF_PREF(pref) ((pref) << 27)
+#define RTF_PREF_MASK  0x18000000
+
 #define RTF_LOCAL      0x80000000
 
+#ifdef __KERNEL__
+#define IPV6_EXTRACT_PREF(flag)        (((flag) & RTF_PREF_MASK) >> 27)
+#define IPV6_DECODE_PREF(pref) ((pref) ^ 2)    /* 1:low,2:med,3:high */
+#endif
+
 struct in6_rtmsg {
        struct in6_addr         rtmsg_dst;
        struct in6_addr         rtmsg_src;
index 95dee17..09d8f10 100644 (file)
@@ -76,6 +76,7 @@ typedef enum {
        IRDA_MCP2120_DONGLE      = 9,
        IRDA_ACT200L_DONGLE      = 10,
        IRDA_MA600_DONGLE        = 11,
+       IRDA_TOIM3232_DONGLE     = 12,
 } IRDA_DONGLE;
 
 /* Protocol types to be used for SOCK_DGRAM */
index cbe7d80..bafe178 100644 (file)
@@ -1,6 +1,6 @@
 #ifdef __KERNEL__
 
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 typedef struct kobject *kobj_probe_t(dev_t, int *, void *);
 struct kobj_map;
@@ -9,6 +9,6 @@ int kobj_map(struct kobj_map *, dev_t, unsigned long, struct module *,
             kobj_probe_t *, int (*)(dev_t, void *), void *);
 void kobj_unmap(struct kobj_map *, dev_t, unsigned long);
 struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *);
-struct kobj_map *kobj_map_init(kobj_probe_t *, struct semaphore *);
+struct kobj_map *kobj_map_init(kobj_probe_t *, struct mutex *);
 
 #endif
index c374b5f..4cb1214 100644 (file)
@@ -80,6 +80,8 @@ extern void kobject_unregister(struct kobject *);
 extern struct kobject * kobject_get(struct kobject *);
 extern void kobject_put(struct kobject *);
 
+extern struct kobject *kobject_add_dir(struct kobject *, const char *);
+
 extern char * kobject_get_path(struct kobject *, gfp_t);
 
 struct kobj_type {
@@ -255,7 +257,7 @@ struct subsys_attribute {
 extern int subsys_create_file(struct subsystem * , struct subsys_attribute *);
 extern void subsys_remove_file(struct subsystem * , struct subsys_attribute *);
 
-#if defined(CONFIG_HOTPLUG) & defined(CONFIG_NET)
+#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
 void kobject_uevent(struct kobject *kobj, enum kobject_action action);
 
 int add_uevent_var(char **envp, int num_envp, int *cur_index,
index c91be5e..239408e 100644 (file)
@@ -35,7 +35,8 @@
 #include <linux/workqueue.h>
 
 /*
- * compile-time options
+ * compile-time options: to be removed as soon as all the drivers are
+ * converted to the new debugging mechanism
  */
 #undef ATA_DEBUG               /* debugging output */
 #undef ATA_VERBOSE_DEBUG       /* yet more debugging output */
 
 #define BPRINTK(fmt, args...) if (ap->flags & ATA_FLAG_DEBUGMSG) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
 
-#ifdef ATA_NDEBUG
-#define assert(expr)
-#else
-#define assert(expr) \
-        if(unlikely(!(expr))) {                                   \
-        printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
-        #expr,__FILE__,__FUNCTION__,__LINE__);          \
-        }
-#endif
+/* NEW: debug levels */
+#define HAVE_LIBATA_MSG 1
+
+enum {
+       ATA_MSG_DRV     = 0x0001,
+       ATA_MSG_INFO    = 0x0002,
+       ATA_MSG_PROBE   = 0x0004,
+       ATA_MSG_WARN    = 0x0008,
+       ATA_MSG_MALLOC  = 0x0010,
+       ATA_MSG_CTL     = 0x0020,
+       ATA_MSG_INTR    = 0x0040,
+       ATA_MSG_ERR     = 0x0080,
+};
+
+#define ata_msg_drv(p)    ((p)->msg_enable & ATA_MSG_DRV)
+#define ata_msg_info(p)   ((p)->msg_enable & ATA_MSG_INFO)
+#define ata_msg_probe(p)  ((p)->msg_enable & ATA_MSG_PROBE)
+#define ata_msg_warn(p)   ((p)->msg_enable & ATA_MSG_WARN)
+#define ata_msg_malloc(p) ((p)->msg_enable & ATA_MSG_MALLOC)
+#define ata_msg_ctl(p)    ((p)->msg_enable & ATA_MSG_CTL)
+#define ata_msg_intr(p)   ((p)->msg_enable & ATA_MSG_INTR)
+#define ata_msg_err(p)    ((p)->msg_enable & ATA_MSG_ERR)
+
+static inline u32 ata_msg_init(int dval, int default_msg_enable_bits)
+{
+       if (dval < 0 || dval >= (sizeof(u32) * 8))
+               return default_msg_enable_bits; /* should be 0x1 - only driver info msgs */
+       if (!dval)
+               return 0;
+       return (1 << dval) - 1;
+}
 
 /* defines only for the constants which don't work well as enums */
 #define ATA_TAG_POISON         0xfafbfcfdU
@@ -99,8 +122,7 @@ enum {
        /* struct ata_device stuff */
        ATA_DFLAG_LBA48         = (1 << 0), /* device supports LBA48 */
        ATA_DFLAG_PIO           = (1 << 1), /* device currently in PIO mode */
-       ATA_DFLAG_LOCK_SECTORS  = (1 << 2), /* don't adjust max_sectors */
-       ATA_DFLAG_LBA           = (1 << 3), /* device supports LBA */
+       ATA_DFLAG_LBA           = (1 << 2), /* device supports LBA */
 
        ATA_DEV_UNKNOWN         = 0,    /* unknown device */
        ATA_DEV_ATA             = 1,    /* ATA device */
@@ -115,9 +137,9 @@ enum {
        ATA_FLAG_PORT_DISABLED  = (1 << 2), /* port is disabled, ignore it */
        ATA_FLAG_SATA           = (1 << 3),
        ATA_FLAG_NO_LEGACY      = (1 << 4), /* no legacy mode check */
-       ATA_FLAG_SRST           = (1 << 5), /* use ATA SRST, not E.D.D. */
+       ATA_FLAG_SRST           = (1 << 5), /* (obsolete) use ATA SRST, not E.D.D. */
        ATA_FLAG_MMIO           = (1 << 6), /* use MMIO, not PIO */
-       ATA_FLAG_SATA_RESET     = (1 << 7), /* use COMRESET */
+       ATA_FLAG_SATA_RESET     = (1 << 7), /* (obsolete) use COMRESET */
        ATA_FLAG_PIO_DMA        = (1 << 8), /* PIO cmds via DMA */
        ATA_FLAG_NOINTR         = (1 << 9), /* FIXME: Remove this once
                                             * proper HSM is in place. */
@@ -129,10 +151,14 @@ enum {
        ATA_FLAG_PIO_LBA48      = (1 << 13), /* Host DMA engine is LBA28 only */
        ATA_FLAG_IRQ_MASK       = (1 << 14), /* Mask IRQ in PIO xfers */
 
+       ATA_FLAG_FLUSH_PORT_TASK = (1 << 15), /* Flush port task */
+       ATA_FLAG_IN_EH          = (1 << 16), /* EH in progress */
+
        ATA_QCFLAG_ACTIVE       = (1 << 1), /* cmd not yet ack'd to scsi lyer */
        ATA_QCFLAG_SG           = (1 << 3), /* have s/g table? */
        ATA_QCFLAG_SINGLE       = (1 << 4), /* no s/g, just a single buffer */
        ATA_QCFLAG_DMAMAP       = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
+       ATA_QCFLAG_EH_SCHEDULED = (1 << 5), /* EH scheduled */
 
        /* various lengths of time */
        ATA_TMOUT_EDD           = 5 * HZ,       /* heuristic */
@@ -162,11 +188,19 @@ enum {
        PORT_DISABLED           = 2,
 
        /* encoding various smaller bitmaps into a single
-        * unsigned long bitmap
+        * unsigned int bitmap
         */
-       ATA_SHIFT_UDMA          = 0,
-       ATA_SHIFT_MWDMA         = 8,
-       ATA_SHIFT_PIO           = 11,
+       ATA_BITS_PIO            = 5,
+       ATA_BITS_MWDMA          = 3,
+       ATA_BITS_UDMA           = 8,
+
+       ATA_SHIFT_PIO           = 0,
+       ATA_SHIFT_MWDMA         = ATA_SHIFT_PIO + ATA_BITS_PIO,
+       ATA_SHIFT_UDMA          = ATA_SHIFT_MWDMA + ATA_BITS_MWDMA,
+
+       ATA_MASK_PIO            = ((1 << ATA_BITS_PIO) - 1) << ATA_SHIFT_PIO,
+       ATA_MASK_MWDMA          = ((1 << ATA_BITS_MWDMA) - 1) << ATA_SHIFT_MWDMA,
+       ATA_MASK_UDMA           = ((1 << ATA_BITS_UDMA) - 1) << ATA_SHIFT_UDMA,
 
        /* size of buffer to pad xfers ending on unaligned boundaries */
        ATA_DMA_PAD_SZ          = 4,
@@ -189,10 +223,15 @@ enum hsm_task_states {
 };
 
 enum ata_completion_errors {
-       AC_ERR_OTHER            = (1 << 0),
-       AC_ERR_DEV              = (1 << 1),
-       AC_ERR_ATA_BUS          = (1 << 2),
-       AC_ERR_HOST_BUS         = (1 << 3),
+       AC_ERR_DEV              = (1 << 0), /* device reported error */
+       AC_ERR_HSM              = (1 << 1), /* host state machine violation */
+       AC_ERR_TIMEOUT          = (1 << 2), /* timeout */
+       AC_ERR_MEDIA            = (1 << 3), /* media error */
+       AC_ERR_ATA_BUS          = (1 << 4), /* ATA bus error */
+       AC_ERR_HOST_BUS         = (1 << 5), /* host bus error */
+       AC_ERR_SYSTEM           = (1 << 6), /* system error */
+       AC_ERR_INVALID          = (1 << 7), /* invalid argument */
+       AC_ERR_OTHER            = (1 << 8), /* unknown */
 };
 
 /* forward declarations */
@@ -202,7 +241,10 @@ struct ata_port;
 struct ata_queued_cmd;
 
 /* typedefs */
-typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
+typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
+typedef void (*ata_probeinit_fn_t)(struct ata_port *);
+typedef int (*ata_reset_fn_t)(struct ata_port *, int, unsigned int *);
+typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *);
 
 struct ata_ioports {
        unsigned long           cmd_addr;
@@ -305,7 +347,7 @@ struct ata_device {
        unsigned long           flags;          /* ATA_DFLAG_xxx */
        unsigned int            class;          /* ATA_DEV_xxx */
        unsigned int            devno;          /* 0 or 1 */
-       u16                     id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+       u16                     *id;            /* IDENTIFY xxx DEVICE data */
        u8                      pio_mode;
        u8                      dma_mode;
        u8                      xfer_mode;
@@ -313,6 +355,8 @@ struct ata_device {
 
        unsigned int            multi_count;    /* sectors count for
                                                   READ/WRITE MULTIPLE */
+       unsigned int            max_sectors;    /* per-device max sectors */
+       unsigned int            cdb_len;
 
        /* for CHS addressing */
        u16                     cylinders;      /* Number of cylinders */
@@ -342,7 +386,6 @@ struct ata_port {
        unsigned int            mwdma_mask;
        unsigned int            udma_mask;
        unsigned int            cbl;    /* cable type; ATA_CBL_xxx */
-       unsigned int            cdb_len;
 
        struct ata_device       device[ATA_MAX_DEVICES];
 
@@ -353,12 +396,14 @@ struct ata_port {
        struct ata_host_stats   stats;
        struct ata_host_set     *host_set;
 
-       struct work_struct      packet_task;
+       struct work_struct      port_task;
 
-       struct work_struct      pio_task;
        unsigned int            hsm_task_state;
        unsigned long           pio_task_timeout;
 
+       u32                     msg_enable;
+       struct list_head        eh_done_q;
+
        void                    *private_data;
 };
 
@@ -378,7 +423,9 @@ struct ata_port_operations {
        u8   (*check_altstatus)(struct ata_port *ap);
        void (*dev_select)(struct ata_port *ap, unsigned int device);
 
-       void (*phy_reset) (struct ata_port *ap);
+       void (*phy_reset) (struct ata_port *ap); /* obsolete */
+       int (*probe_reset) (struct ata_port *ap, unsigned int *classes);
+
        void (*post_set_mode) (struct ata_port *ap);
 
        int (*check_atapi_dma) (struct ata_queued_cmd *qc);
@@ -387,7 +434,7 @@ struct ata_port_operations {
        void (*bmdma_start) (struct ata_queued_cmd *qc);
 
        void (*qc_prep) (struct ata_queued_cmd *qc);
-       int (*qc_issue) (struct ata_queued_cmd *qc);
+       unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
 
        void (*eng_timeout) (struct ata_port *ap);
 
@@ -435,6 +482,18 @@ extern void ata_port_probe(struct ata_port *);
 extern void __sata_phy_reset(struct ata_port *ap);
 extern void sata_phy_reset(struct ata_port *ap);
 extern void ata_bus_reset(struct ata_port *ap);
+extern int ata_drive_probe_reset(struct ata_port *ap,
+                       ata_probeinit_fn_t probeinit,
+                       ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+                       ata_postreset_fn_t postreset, unsigned int *classes);
+extern void ata_std_probeinit(struct ata_port *ap);
+extern int ata_std_softreset(struct ata_port *ap, int verbose,
+                            unsigned int *classes);
+extern int sata_std_hardreset(struct ata_port *ap, int verbose,
+                             unsigned int *class);
+extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
+extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
+                             int post_reset);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
 #ifdef CONFIG_PCI
@@ -449,7 +508,10 @@ extern void ata_host_set_remove(struct ata_host_set *host_set);
 extern int ata_scsi_detect(struct scsi_host_template *sht);
 extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
 extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern int ata_scsi_error(struct Scsi_Host *host);
+extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
+extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
 extern int ata_scsi_release(struct Scsi_Host *host);
 extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
 extern int ata_scsi_device_resume(struct scsi_device *);
@@ -457,6 +519,11 @@ extern int ata_scsi_device_suspend(struct scsi_device *);
 extern int ata_device_resume(struct ata_port *, struct ata_device *);
 extern int ata_device_suspend(struct ata_port *, struct ata_device *);
 extern int ata_ratelimit(void);
+extern unsigned int ata_busy_sleep(struct ata_port *ap,
+                                  unsigned long timeout_pat,
+                                  unsigned long timeout);
+extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *),
+                               void *data, unsigned long delay);
 
 /*
  * Default driver ops implementations
@@ -470,26 +537,28 @@ extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
 extern u8 ata_check_status(struct ata_port *ap);
 extern u8 ata_altstatus(struct ata_port *ap);
 extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf);
+extern int ata_std_probe_reset(struct ata_port *ap, unsigned int *classes);
 extern int ata_port_start (struct ata_port *ap);
 extern void ata_port_stop (struct ata_port *ap);
 extern void ata_host_stop (struct ata_host_set *host_set);
 extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
 extern void ata_qc_prep(struct ata_queued_cmd *qc);
-extern int ata_qc_issue_prot(struct ata_queued_cmd *qc);
+extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
 extern void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf,
                unsigned int buflen);
 extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
                 unsigned int n_elem);
 extern unsigned int ata_dev_classify(const struct ata_taskfile *tf);
-extern void ata_dev_id_string(const u16 *id, unsigned char *s,
-                             unsigned int ofs, unsigned int len);
-extern void ata_dev_config(struct ata_port *ap, unsigned int i);
+extern void ata_id_string(const u16 *id, unsigned char *s,
+                         unsigned int ofs, unsigned int len);
+extern void ata_id_c_string(const u16 *id, unsigned char *s,
+                           unsigned int ofs, unsigned int len);
 extern void ata_bmdma_setup (struct ata_queued_cmd *qc);
 extern void ata_bmdma_start (struct ata_queued_cmd *qc);
 extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
 extern u8   ata_bmdma_status(struct ata_port *ap);
 extern void ata_bmdma_irq_clear(struct ata_port *ap);
-extern void ata_qc_complete(struct ata_queued_cmd *qc);
+extern void __ata_qc_complete(struct ata_queued_cmd *qc);
 extern void ata_eng_timeout(struct ata_port *ap);
 extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
                              struct scsi_cmnd *cmd,
@@ -586,10 +655,14 @@ static inline unsigned int ata_tag_valid(unsigned int tag)
        return (tag < ATA_MAX_QUEUE) ? 1 : 0;
 }
 
+static inline unsigned int ata_class_present(unsigned int class)
+{
+       return class == ATA_DEV_ATA || class == ATA_DEV_ATAPI;
+}
+
 static inline unsigned int ata_dev_present(const struct ata_device *dev)
 {
-       return ((dev->class == ATA_DEV_ATA) ||
-               (dev->class == ATA_DEV_ATAPI));
+       return ata_class_present(dev->class);
 }
 
 static inline u8 ata_chk_status(struct ata_port *ap)
@@ -657,9 +730,9 @@ static inline u8 ata_wait_idle(struct ata_port *ap)
 
        if (status & (ATA_BUSY | ATA_DRQ)) {
                unsigned long l = ap->ioaddr.status_addr;
-               printk(KERN_WARNING
-                      "ATA: abnormal status 0x%X on port 0x%lX\n",
-                      status, l);
+               if (ata_msg_warn(ap))
+                       printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n",
+                               status, l);
        }
 
        return status;
@@ -701,6 +774,24 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
        ata_tf_init(qc->ap, &qc->tf, qc->dev->devno);
 }
 
+/**
+ *     ata_qc_complete - Complete an active ATA command
+ *     @qc: Command to complete
+ *     @err_mask: ATA Status register contents
+ *
+ *     Indicate to the mid and upper layers that an ATA
+ *     command has completed, with either an ok or not-ok status.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host_set lock)
+ */
+static inline void ata_qc_complete(struct ata_queued_cmd *qc)
+{
+       if (unlikely(qc->flags & ATA_QCFLAG_EH_SCHEDULED))
+               return;
+
+       __ata_qc_complete(qc);
+}
 
 /**
  *     ata_irq_on - Enable interrupts on a port.
@@ -751,7 +842,8 @@ static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
 
        status = ata_busy_wait(ap, bits, 1000);
        if (status & bits)
-               DPRINTK("abnormal status 0x%X\n", status);
+               if (ata_msg_err(ap))
+                       printk(KERN_ERR "abnormal status 0x%X\n", status);
 
        /* get controller status; clear intr, err bits */
        if (ap->flags & ATA_FLAG_MMIO) {
@@ -769,8 +861,10 @@ static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
                post_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
        }
 
-       VPRINTK("irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
-               host_stat, post_stat, status);
+       if (ata_msg_intr(ap))
+               printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
+                       __FUNCTION__,
+                       host_stat, post_stat, status);
 
        return status;
 }
@@ -807,7 +901,7 @@ static inline int ata_try_flush_cache(const struct ata_device *dev)
 static inline unsigned int ac_err_mask(u8 status)
 {
        if (status & ATA_BUSY)
-               return AC_ERR_ATA_BUS;
+               return AC_ERR_HSM;
        if (status & (ATA_ERR | ATA_DF))
                return AC_ERR_DEV;
        return 0;
index 47208bd..67258b4 100644 (file)
@@ -411,6 +411,17 @@ static inline void list_splice_init(struct list_head *list,
             pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
+ * list_for_each_entry_from -  iterate over list of given type
+ *                     continuing from existing point
+ * @pos:       the type * to use as a loop counter.
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_from(pos, head, member)                    \
+       for (; prefetch(pos->member.next), &pos->member != (head);      \
+            pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
  * @pos:       the type * to use as a loop counter.
  * @n:         another type * to use as temporary storage
@@ -438,6 +449,19 @@ static inline void list_splice_init(struct list_head *list,
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
+ * list_for_each_entry_safe_from - iterate over list of given type
+ *                     from existing point safe against removal of list entry
+ * @pos:       the type * to use as a loop counter.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member)                    \
+       for (n = list_entry(pos->member.next, typeof(*pos), member);            \
+            &pos->member != (head);                                            \
+            pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
  * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
  *                                   removal of list entry
  * @pos:       the type * to use as a loop counter.
index 84d75f3..70bd843 100644 (file)
@@ -198,6 +198,9 @@ void *__symbol_get_gpl(const char *symbol);
 #define EXPORT_SYMBOL_GPL(sym)                                 \
        __EXPORT_SYMBOL(sym, "_gpl")
 
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)                          \
+       __EXPORT_SYMBOL(sym, "_gpl_future")
+
 #endif
 
 struct module_ref
@@ -242,6 +245,7 @@ struct module
        /* Sysfs stuff. */
        struct module_kobject mkobj;
        struct module_param_attrs *param_attrs;
+       struct module_attribute *modinfo_attrs;
        const char *version;
        const char *srcversion;
 
@@ -255,6 +259,11 @@ struct module
        unsigned int num_gpl_syms;
        const unsigned long *gpl_crcs;
 
+       /* symbols that will be GPL-only in the near future. */
+       const struct kernel_symbol *gpl_future_syms;
+       unsigned int num_gpl_future_syms;
+       const unsigned long *gpl_future_crcs;
+
        /* Exception table */
        unsigned int num_exentries;
        const struct exception_table_entry *extable;
@@ -441,6 +450,7 @@ void module_remove_driver(struct device_driver *);
 #else /* !CONFIG_MODULES... */
 #define EXPORT_SYMBOL(sym)
 #define EXPORT_SYMBOL_GPL(sym)
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)
 
 /* Given an address, look for it in the exception tables. */
 static inline const struct exception_table_entry *
index 28195a2..152fa65 100644 (file)
@@ -149,6 +149,10 @@ struct proto_ops {
                                      int optname, char __user *optval, int optlen);
        int             (*getsockopt)(struct socket *sock, int level,
                                      int optname, char __user *optval, int __user *optlen);
+       int             (*compat_setsockopt)(struct socket *sock, int level,
+                                     int optname, char __user *optval, int optlen);
+       int             (*compat_getsockopt)(struct socket *sock, int level,
+                                     int optname, char __user *optval, int __user *optlen);
        int             (*sendmsg)   (struct kiocb *iocb, struct socket *sock,
                                      struct msghdr *m, size_t total_len);
        int             (*recvmsg)   (struct kiocb *iocb, struct socket *sock,
index 7fda03d..950dc55 100644 (file)
@@ -230,7 +230,8 @@ enum netdev_state_t
        __LINK_STATE_SCHED,
        __LINK_STATE_NOCARRIER,
        __LINK_STATE_RX_SCHED,
-       __LINK_STATE_LINKWATCH_PENDING
+       __LINK_STATE_LINKWATCH_PENDING,
+       __LINK_STATE_DORMANT,
 };
 
 
@@ -335,11 +336,14 @@ struct net_device
         */
 
 
-       unsigned short          flags;  /* interface flags (a la BSD)   */
+       unsigned int            flags;  /* interface flags (a la BSD)   */
        unsigned short          gflags;
         unsigned short          priv_flags; /* Like 'flags' but invisible to userspace. */
        unsigned short          padded; /* How much padding added by alloc_netdev() */
 
+       unsigned char           operstate; /* RFC2863 operstate */
+       unsigned char           link_mode; /* mapping policy to operstate */
+
        unsigned                mtu;    /* interface MTU value          */
        unsigned short          type;   /* interface hardware type      */
        unsigned short          hard_header_len;        /* hardware hdr length  */
@@ -708,12 +712,18 @@ static inline void dev_put(struct net_device *dev)
        atomic_dec(&dev->refcnt);
 }
 
-#define __dev_put(dev) atomic_dec(&(dev)->refcnt)
-#define dev_hold(dev) atomic_inc(&(dev)->refcnt)
+static inline void dev_hold(struct net_device *dev)
+{
+       atomic_inc(&dev->refcnt);
+}
 
 /* Carrier loss detection, dial on demand. The functions netif_carrier_on
  * and _off may be called from IRQ context, but it is caller
  * who is responsible for serialization of these calls.
+ *
+ * The name carrier is inappropriate, these functions should really be
+ * called netif_lowerlayer_*() because they represent the state of any
+ * kind of lower layer not just hardware media.
  */
 
 extern void linkwatch_fire_event(struct net_device *dev);
@@ -729,6 +739,29 @@ extern void netif_carrier_on(struct net_device *dev);
 
 extern void netif_carrier_off(struct net_device *dev);
 
+static inline void netif_dormant_on(struct net_device *dev)
+{
+       if (!test_and_set_bit(__LINK_STATE_DORMANT, &dev->state))
+               linkwatch_fire_event(dev);
+}
+
+static inline void netif_dormant_off(struct net_device *dev)
+{
+       if (test_and_clear_bit(__LINK_STATE_DORMANT, &dev->state))
+               linkwatch_fire_event(dev);
+}
+
+static inline int netif_dormant(const struct net_device *dev)
+{
+       return test_bit(__LINK_STATE_DORMANT, &dev->state);
+}
+
+
+static inline int netif_oper_up(const struct net_device *dev) {
+       return (dev->operstate == IF_OPER_UP ||
+               dev->operstate == IF_OPER_UNKNOWN /* backward compat */);
+}
+
 /* Hot-plugging. */
 static inline int netif_device_present(struct net_device *dev)
 {
index 4688969..412e52c 100644 (file)
@@ -80,10 +80,14 @@ struct nf_sockopt_ops
        int set_optmin;
        int set_optmax;
        int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len);
+       int (*compat_set)(struct sock *sk, int optval,
+                       void __user *user, unsigned int len);
 
        int get_optmin;
        int get_optmax;
        int (*get)(struct sock *sk, int optval, void __user *user, int *len);
+       int (*compat_get)(struct sock *sk, int optval,
+                       void __user *user, int *len);
 
        /* Number of users inside set() or get(). */
        unsigned int use;
@@ -246,6 +250,11 @@ int nf_setsockopt(struct sock *sk, int pf, int optval, char __user *opt,
 int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt,
                  int *len);
 
+int compat_nf_setsockopt(struct sock *sk, int pf, int optval,
+               char __user *opt, int len);
+int compat_nf_getsockopt(struct sock *sk, int pf, int optval,
+               char __user *opt, int *len);
+
 /* Packet queuing */
 struct nf_queue_handler {
        int (*outfn)(struct sk_buff *skb, struct nf_info *info,
index 934a247..9f5b12c 100644 (file)
@@ -164,6 +164,7 @@ extern void nfattr_parse(struct nfattr *tb[], int maxattr,
        __res;                                                          \
 })
 
+extern int nfnetlink_has_listeners(unsigned int group);
 extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, 
                          int echo);
 extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
index b04b038..a7497c7 100644 (file)
@@ -47,6 +47,8 @@ enum nfulnl_attr_type {
        NFULA_PAYLOAD,                  /* opaque data payload */
        NFULA_PREFIX,                   /* string prefix */
        NFULA_UID,                      /* user id of socket */
+       NFULA_SEQ,                      /* instance-local sequence number */
+       NFULA_SEQ_GLOBAL,               /* global sequence number */
 
        __NFULA_MAX
 };
@@ -77,6 +79,7 @@ enum nfulnl_attr_config {
        NFULA_CFG_NLBUFSIZ,             /* u_int32_t buffer size */
        NFULA_CFG_TIMEOUT,              /* u_int32_t in 1/100 s */
        NFULA_CFG_QTHRESH,              /* u_int32_t */
+       NFULA_CFG_FLAGS,                /* u_int16_t */
        __NFULA_CFG_MAX
 };
 #define NFULA_CFG_MAX (__NFULA_CFG_MAX -1)
@@ -85,4 +88,7 @@ enum nfulnl_attr_config {
 #define NFULNL_COPY_META       0x01
 #define NFULNL_COPY_PACKET     0x02
 
+#define NFULNL_CFG_F_SEQ       0x0001
+#define NFULNL_CFG_F_SEQ_GLOBAL        0x0002
+
 #endif /* _NFNETLINK_LOG_H */
index 6500d4e..46a0f97 100644 (file)
@@ -92,8 +92,6 @@ struct xt_match
 
        const char name[XT_FUNCTION_MAXNAMELEN-1];
 
-       u_int8_t revision;
-
        /* Return true or false: return FALSE and set *hotdrop = 1 to
            force immediate packet drop. */
        /* Arguments changed since 2.6.9, as this must now handle
@@ -102,6 +100,7 @@ struct xt_match
        int (*match)(const struct sk_buff *skb,
                     const struct net_device *in,
                     const struct net_device *out,
+                    const struct xt_match *match,
                     const void *matchinfo,
                     int offset,
                     unsigned int protoff,
@@ -111,15 +110,25 @@ struct xt_match
        /* Should return true or false. */
        int (*checkentry)(const char *tablename,
                          const void *ip,
+                         const struct xt_match *match,
                          void *matchinfo,
                          unsigned int matchinfosize,
                          unsigned int hook_mask);
 
        /* Called when entry of this type deleted. */
-       void (*destroy)(void *matchinfo, unsigned int matchinfosize);
+       void (*destroy)(const struct xt_match *match, void *matchinfo,
+                       unsigned int matchinfosize);
 
        /* Set this to THIS_MODULE if you are a module, otherwise NULL */
        struct module *me;
+
+       char *table;
+       unsigned int matchsize;
+       unsigned int hooks;
+       unsigned short proto;
+
+       unsigned short family;
+       u_int8_t revision;
 };
 
 /* Registration hooks for targets. */
@@ -129,8 +138,6 @@ struct xt_target
 
        const char name[XT_FUNCTION_MAXNAMELEN-1];
 
-       u_int8_t revision;
-
        /* Returns verdict. Argument order changed since 2.6.9, as this
           must now handle non-linear skbs, using skb_copy_bits and
           skb_ip_make_writable. */
@@ -138,6 +145,7 @@ struct xt_target
                               const struct net_device *in,
                               const struct net_device *out,
                               unsigned int hooknum,
+                              const struct xt_target *target,
                               const void *targinfo,
                               void *userdata);
 
@@ -147,15 +155,25 @@ struct xt_target
        /* Should return true or false. */
        int (*checkentry)(const char *tablename,
                          const void *entry,
+                         const struct xt_target *target,
                          void *targinfo,
                          unsigned int targinfosize,
                          unsigned int hook_mask);
 
        /* Called when entry of this type deleted. */
-       void (*destroy)(void *targinfo, unsigned int targinfosize);
+       void (*destroy)(const struct xt_target *target, void *targinfo,
+                       unsigned int targinfosize);
 
        /* Set this to THIS_MODULE if you are a module, otherwise NULL */
        struct module *me;
+
+       char *table;
+       unsigned int targetsize;
+       unsigned int hooks;
+       unsigned short proto;
+
+       unsigned short family;
+       u_int8_t revision;
 };
 
 /* Furniture shopping... */
@@ -207,6 +225,13 @@ extern void xt_unregister_target(int af, struct xt_target *target);
 extern int xt_register_match(int af, struct xt_match *target);
 extern void xt_unregister_match(int af, struct xt_match *target);
 
+extern int xt_check_match(const struct xt_match *match, unsigned short family,
+                         unsigned int size, const char *table, unsigned int hook,
+                         unsigned short proto, int inv_proto);
+extern int xt_check_target(const struct xt_target *target, unsigned short family,
+                          unsigned int size, const char *table, unsigned int hook,
+                          unsigned short proto, int inv_proto);
+
 extern int xt_register_table(struct xt_table *table,
                             struct xt_table_info *bootstrap,
                             struct xt_table_info *newinfo);
diff --git a/include/linux/netfilter/xt_policy.h b/include/linux/netfilter/xt_policy.h
new file mode 100644 (file)
index 0000000..a8132ec
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _XT_POLICY_H
+#define _XT_POLICY_H
+
+#define XT_POLICY_MAX_ELEM     4
+
+enum xt_policy_flags
+{
+       XT_POLICY_MATCH_IN      = 0x1,
+       XT_POLICY_MATCH_OUT     = 0x2,
+       XT_POLICY_MATCH_NONE    = 0x4,
+       XT_POLICY_MATCH_STRICT  = 0x8,
+};
+
+enum xt_policy_modes
+{
+       XT_POLICY_MODE_TRANSPORT,
+       XT_POLICY_MODE_TUNNEL
+};
+
+struct xt_policy_spec
+{
+       u_int8_t        saddr:1,
+                       daddr:1,
+                       proto:1,
+                       mode:1,
+                       spi:1,
+                       reqid:1;
+};
+
+union xt_policy_addr
+{
+       struct in_addr  a4;
+       struct in6_addr a6;
+};
+
+struct xt_policy_elem
+{
+       union xt_policy_addr    saddr;
+       union xt_policy_addr    smask;
+       union xt_policy_addr    daddr;
+       union xt_policy_addr    dmask;
+       u_int32_t               spi;
+       u_int32_t               reqid;
+       u_int8_t                proto;
+       u_int8_t                mode;
+
+       struct xt_policy_spec   match;
+       struct xt_policy_spec   invert;
+};
+
+struct xt_policy_info
+{
+       struct xt_policy_elem pol[XT_POLICY_MAX_ELEM];
+       u_int16_t flags;
+       u_int16_t len;
+};
+
+#endif /* _XT_POLICY_H */
index de4d397..a75b84b 100644 (file)
@@ -47,22 +47,6 @@ enum nf_br_hook_priorities {
 #define BRNF_BRIDGED                   0x08
 #define BRNF_NF_BRIDGE_PREROUTING      0x10
 
-static inline
-struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
-{
-       struct nf_bridge_info **nf_bridge = &(skb->nf_bridge);
-
-       if ((*nf_bridge = kmalloc(sizeof(**nf_bridge), GFP_ATOMIC)) != NULL) {
-               atomic_set(&(*nf_bridge)->use, 1);
-               (*nf_bridge)->mask = 0;
-               (*nf_bridge)->physindev = (*nf_bridge)->physoutdev = NULL;
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-               (*nf_bridge)->netoutdev = NULL;
-#endif
-       }
-
-       return *nf_bridge;
-}
 
 /* Only used in br_forward.c */
 static inline
@@ -77,17 +61,6 @@ void nf_bridge_maybe_copy_header(struct sk_buff *skb)
        }
 }
 
-static inline
-void nf_bridge_save_header(struct sk_buff *skb)
-{
-        int header_size = 16;
-
-       if (skb->protocol == __constant_htons(ETH_P_8021Q))
-               header_size = 18;
-
-       memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
-}
-
 /* This is called by the IP fragmenting code and it ensures there is
  * enough room for the encapsulating header (if there is one). */
 static inline
index 215765f..f32d75c 100644 (file)
@@ -29,6 +29,7 @@ union ip_conntrack_expect_proto {
 };
 
 /* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
 #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
@@ -37,6 +38,7 @@ union ip_conntrack_expect_proto {
 /* per conntrack: application helper private data */
 union ip_conntrack_help {
        /* insert conntrack helper private data (master) here */
+       struct ip_ct_h323_master ct_h323_info;
        struct ip_ct_pptp_master ct_pptp_info;
        struct ip_ct_ftp_master ct_ftp_info;
        struct ip_ct_irc_master ct_irc_info;
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
new file mode 100644 (file)
index 0000000..0987cea
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _IP_CONNTRACK_H323_H
+#define _IP_CONNTRACK_H323_H
+
+#ifdef __KERNEL__
+
+#define RAS_PORT 1719
+#define Q931_PORT 1720
+#define H323_RTP_CHANNEL_MAX 4 /* Audio, video, FAX and other */
+
+/* This structure exists only once per master */
+struct ip_ct_h323_master {
+
+       /* Original and NATed Q.931 or H.245 signal ports */
+       u_int16_t sig_port[IP_CT_DIR_MAX];
+
+       /* Original and NATed RTP ports */
+       u_int16_t rtp_port[H323_RTP_CHANNEL_MAX][IP_CT_DIR_MAX];
+
+       union {
+               /* RAS connection timeout */
+               u_int32_t timeout;
+
+               /* Next TPKT length (for separate TPKT header and data) */
+               u_int16_t tpkt_len[IP_CT_DIR_MAX];
+       };
+};
+
+#endif
+
+#endif
index 41a107d..e9f5ed1 100644 (file)
@@ -23,7 +23,7 @@ struct ip_nat_seq {
         * modification (if any) */
        u_int32_t correction_pos;
        /* sequence number offset before and after last modification */
-       int32_t offset_before, offset_after;
+       int16_t offset_before, offset_after;
 };
 
 /* Single range specification. */
index a3f6eff..b9478a2 100644 (file)
@@ -1,58 +1,21 @@
 #ifndef _IPT_POLICY_H
 #define _IPT_POLICY_H
 
-#define IPT_POLICY_MAX_ELEM    4
-
-enum ipt_policy_flags
-{
-       IPT_POLICY_MATCH_IN     = 0x1,
-       IPT_POLICY_MATCH_OUT    = 0x2,
-       IPT_POLICY_MATCH_NONE   = 0x4,
-       IPT_POLICY_MATCH_STRICT = 0x8,
-};
-
-enum ipt_policy_modes
-{
-       IPT_POLICY_MODE_TRANSPORT,
-       IPT_POLICY_MODE_TUNNEL
-};
-
-struct ipt_policy_spec
-{
-       u_int8_t        saddr:1,
-                       daddr:1,
-                       proto:1,
-                       mode:1,
-                       spi:1,
-                       reqid:1;
-};
-
-union ipt_policy_addr
-{
-       struct in_addr  a4;
-       struct in6_addr a6;
-};
-
-struct ipt_policy_elem
-{
-       union ipt_policy_addr   saddr;
-       union ipt_policy_addr   smask;
-       union ipt_policy_addr   daddr;
-       union ipt_policy_addr   dmask;
-       u_int32_t               spi;
-       u_int32_t               reqid;
-       u_int8_t                proto;
-       u_int8_t                mode;
-
-       struct ipt_policy_spec  match;
-       struct ipt_policy_spec  invert;
-};
-
-struct ipt_policy_info
-{
-       struct ipt_policy_elem pol[IPT_POLICY_MAX_ELEM];
-       u_int16_t flags;
-       u_int16_t len;
-};
+#define IPT_POLICY_MAX_ELEM            XT_POLICY_MAX_ELEM
+
+/* ipt_policy_flags */
+#define IPT_POLICY_MATCH_IN            XT_POLICY_MATCH_IN
+#define IPT_POLICY_MATCH_OUT           XT_POLICY_MATCH_OUT
+#define IPT_POLICY_MATCH_NONE          XT_POLICY_MATCH_NONE
+#define IPT_POLICY_MATCH_STRICT                XT_POLICY_MATCH_STRICT
+
+/* ipt_policy_modes */
+#define IPT_POLICY_MODE_TRANSPORT      XT_POLICY_MODE_TRANSPORT
+#define IPT_POLICY_MODE_TUNNEL         XT_POLICY_MODE_TUNNEL
+
+#define ipt_policy_spec                        xt_policy_spec
+#define ipt_policy_addr                        xt_policy_addr
+#define ipt_policy_elem                        xt_policy_elem
+#define ipt_policy_info                        xt_policy_info
 
 #endif /* _IPT_POLICY_H */
index 671bd81..6bab316 100644 (file)
@@ -1,58 +1,21 @@
 #ifndef _IP6T_POLICY_H
 #define _IP6T_POLICY_H
 
-#define IP6T_POLICY_MAX_ELEM   4
-
-enum ip6t_policy_flags
-{
-       IP6T_POLICY_MATCH_IN            = 0x1,
-       IP6T_POLICY_MATCH_OUT           = 0x2,
-       IP6T_POLICY_MATCH_NONE          = 0x4,
-       IP6T_POLICY_MATCH_STRICT        = 0x8,
-};
-
-enum ip6t_policy_modes
-{
-       IP6T_POLICY_MODE_TRANSPORT,
-       IP6T_POLICY_MODE_TUNNEL
-};
-
-struct ip6t_policy_spec
-{
-       u_int8_t        saddr:1,
-                       daddr:1,
-                       proto:1,
-                       mode:1,
-                       spi:1,
-                       reqid:1;
-};
-
-union ip6t_policy_addr
-{
-       struct in_addr  a4;
-       struct in6_addr a6;
-};
-
-struct ip6t_policy_elem
-{
-       union ip6t_policy_addr  saddr;
-       union ip6t_policy_addr  smask;
-       union ip6t_policy_addr  daddr;
-       union ip6t_policy_addr  dmask;
-       u_int32_t               spi;
-       u_int32_t               reqid;
-       u_int8_t                proto;
-       u_int8_t                mode;
-
-       struct ip6t_policy_spec match;
-       struct ip6t_policy_spec invert;
-};
-
-struct ip6t_policy_info
-{
-       struct ip6t_policy_elem pol[IP6T_POLICY_MAX_ELEM];
-       u_int16_t flags;
-       u_int16_t len;
-};
+#define IP6T_POLICY_MAX_ELEM           XT_POLICY_MAX_ELEM
+
+/* ip6t_policy_flags */
+#define IP6T_POLICY_MATCH_IN           XT_POLICY_MATCH_IN
+#define IP6T_POLICY_MATCH_OUT          XT_POLICY_MATCH_OUT
+#define IP6T_POLICY_MATCH_NONE         XT_POLICY_MATCH_NONE
+#define IP6T_POLICY_MATCH_STRICT       XT_POLICY_MATCH_STRICT
+
+/* ip6t_policy_modes */
+#define IP6T_POLICY_MODE_TRANSPORT     XT_POLICY_MODE_TRANSPORT
+#define IP6T_POLICY_MODE_TUNNEL                XT_POLICY_MODE_TUNNEL
+
+#define ip6t_policy_spec               xt_policy_spec
+#define ip6t_policy_addr               xt_policy_addr
+#define ip6t_policy_elem               xt_policy_elem
+#define ip6t_policy_info               xt_policy_info
 
 #endif /* _IP6T_POLICY_H */
index c256ebe..f8f3d1c 100644 (file)
@@ -151,6 +151,7 @@ struct netlink_skb_parms
 
 extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
 extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
+extern int netlink_has_listeners(struct sock *sk, unsigned int group);
 extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
 extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
                             __u32 group, gfp_t allocation);
index 751eea5..b9810dd 100644 (file)
 #define PCI_DEVICE_ID_TIGON3_5705M     0x165d
 #define PCI_DEVICE_ID_TIGON3_5705M_2   0x165e
 #define PCI_DEVICE_ID_TIGON3_5714      0x1668
+#define PCI_DEVICE_ID_TIGON3_5714S     0x1669
 #define PCI_DEVICE_ID_TIGON3_5780      0x166a
 #define PCI_DEVICE_ID_TIGON3_5780S     0x166b
 #define PCI_DEVICE_ID_TIGON3_5705F     0x166e
+#define PCI_DEVICE_ID_TIGON3_5754M     0x1672
 #define PCI_DEVICE_ID_TIGON3_5750      0x1676
 #define PCI_DEVICE_ID_TIGON3_5751      0x1677
 #define PCI_DEVICE_ID_TIGON3_5715      0x1678
+#define PCI_DEVICE_ID_TIGON3_5715S     0x1679
+#define PCI_DEVICE_ID_TIGON3_5754      0x167a
 #define PCI_DEVICE_ID_TIGON3_5750M     0x167c
 #define PCI_DEVICE_ID_TIGON3_5751M     0x167d
 #define PCI_DEVICE_ID_TIGON3_5751F     0x167e
+#define PCI_DEVICE_ID_TIGON3_5787M     0x1693
 #define PCI_DEVICE_ID_TIGON3_5782      0x1696
+#define PCI_DEVICE_ID_TIGON3_5787      0x169b
 #define PCI_DEVICE_ID_TIGON3_5788      0x169c
 #define PCI_DEVICE_ID_TIGON3_5789      0x169d
 #define PCI_DEVICE_ID_TIGON3_5702X     0x16a6
index d50482b..d572d53 100644 (file)
@@ -199,6 +199,7 @@ enum
 #define RTPROT_BIRD    12      /* BIRD */
 #define RTPROT_DNROUTED        13      /* DECnet routing daemon */
 #define RTPROT_XORP    14      /* XORP */
+#define RTPROT_NTK     15      /* Netsukuku */
 
 /* rtm_scope
 
@@ -733,6 +734,8 @@ enum
 #define IFLA_MAP IFLA_MAP
        IFLA_WEIGHT,
 #define IFLA_WEIGHT IFLA_WEIGHT
+       IFLA_OPERSTATE,
+       IFLA_LINKMODE,
        __IFLA_MAX
 };
 
@@ -905,6 +908,7 @@ struct tcamsg
 #ifdef __KERNEL__
 
 #include <linux/config.h>
+#include <linux/mutex.h>
 
 extern size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size);
 static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
@@ -1036,24 +1040,17 @@ __rta_reserve(struct sk_buff *skb, int attrtype, int attrlen)
 
 extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change);
 
-extern struct semaphore rtnl_sem;
-
-#define rtnl_shlock()          down(&rtnl_sem)
-#define rtnl_shlock_nowait()   down_trylock(&rtnl_sem)
-
-#define rtnl_shunlock()        do { up(&rtnl_sem); \
-                            if (rtnl && rtnl->sk_receive_queue.qlen) \
-                                    rtnl->sk_data_ready(rtnl, 0); \
-                       } while(0)
-
+/* RTNL is used as a global lock for all changes to network configuration  */
 extern void rtnl_lock(void);
-extern int rtnl_lock_interruptible(void);
 extern void rtnl_unlock(void);
+extern int rtnl_trylock(void);
+
 extern void rtnetlink_init(void);
+extern void __rtnl_unlock(void);
 
 #define ASSERT_RTNL() do { \
-       if (unlikely(down_trylock(&rtnl_sem) == 0)) { \
-               up(&rtnl_sem); \
+       if (unlikely(rtnl_trylock())) { \
+               rtnl_unlock(); \
                printk(KERN_ERR "RTNL: assertion failed at %s (%d)\n", \
                       __FILE__,  __LINE__); \
                dump_stack(); \
index 7cbef48..b18eb8c 100644 (file)
@@ -1286,7 +1286,8 @@ struct security_operations {
        int (*socket_setsockopt) (struct socket * sock, int level, int optname);
        int (*socket_shutdown) (struct socket * sock, int how);
        int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
-       int (*socket_getpeersec) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
+       int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
+       int (*socket_getpeersec_dgram) (struct sk_buff *skb, char **secdata, u32 *seclen);
        int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
        void (*sk_free_security) (struct sock *sk);
        unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir);
@@ -2741,10 +2742,16 @@ static inline int security_sock_rcv_skb (struct sock * sk,
        return security_ops->socket_sock_rcv_skb (sk, skb);
 }
 
-static inline int security_socket_getpeersec(struct socket *sock, char __user *optval,
-                                            int __user *optlen, unsigned len)
+static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
+                                                   int __user *optlen, unsigned len)
 {
-       return security_ops->socket_getpeersec(sock, optval, optlen, len);
+       return security_ops->socket_getpeersec_stream(sock, optval, optlen, len);
+}
+
+static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
+                                                  u32 *seclen)
+{
+       return security_ops->socket_getpeersec_dgram(skb, secdata, seclen);
 }
 
 static inline int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
@@ -2863,8 +2870,14 @@ static inline int security_sock_rcv_skb (struct sock * sk,
        return 0;
 }
 
-static inline int security_socket_getpeersec(struct socket *sock, char __user *optval,
-                                            int __user *optlen, unsigned len)
+static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
+                                                   int __user *optlen, unsigned len)
+{
+       return -ENOPROTOOPT;
+}
+
+static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
+                                                  u32 *seclen)
 {
        return -ENOPROTOOPT;
 }
index ad7cc22..613b951 100644 (file)
@@ -270,7 +270,6 @@ struct sk_buff {
 
        void                    (*destructor)(struct sk_buff *skb);
 #ifdef CONFIG_NETFILTER
-       __u32                   nfmark;
        struct nf_conntrack     *nfct;
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        struct sk_buff          *nfct_reasm;
@@ -278,6 +277,7 @@ struct sk_buff {
 #ifdef CONFIG_BRIDGE_NETFILTER
        struct nf_bridge_info   *nf_bridge;
 #endif
+       __u32                   nfmark;
 #endif /* CONFIG_NETFILTER */
 #ifdef CONFIG_NET_SCHED
        __u16                   tc_index;       /* traffic control index */
@@ -304,6 +304,7 @@ struct sk_buff {
 
 #include <asm/system.h>
 
+extern void kfree_skb(struct sk_buff *skb);
 extern void           __kfree_skb(struct sk_buff *skb);
 extern struct sk_buff *__alloc_skb(unsigned int size,
                                   gfp_t priority, int fclone);
@@ -404,22 +405,6 @@ static inline struct sk_buff *skb_get(struct sk_buff *skb)
  */
 
 /**
- *     kfree_skb - free an sk_buff
- *     @skb: buffer to free
- *
- *     Drop a reference to the buffer and free it if the usage count has
- *     hit zero.
- */
-static inline void kfree_skb(struct sk_buff *skb)
-{
-       if (likely(atomic_read(&skb->users) == 1))
-               smp_rmb();
-       else if (likely(!atomic_dec_and_test(&skb->users)))
-               return;
-       __kfree_skb(skb);
-}
-
-/**
  *     skb_cloned - is the buffer a clone
  *     @skb: buffer to check
  *
@@ -1174,12 +1159,14 @@ static inline int skb_linearize(struct sk_buff *skb, gfp_t gfp)
  */
 
 static inline void skb_postpull_rcsum(struct sk_buff *skb,
-                                        const void *start, int len)
+                                     const void *start, unsigned int len)
 {
        if (skb->ip_summed == CHECKSUM_HW)
                skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0));
 }
 
+unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len);
+
 /**
  *     pskb_trim_rcsum - trim received skb and update checksum
  *     @skb: buffer to trim
@@ -1351,16 +1338,6 @@ static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
                kfree_skb(skb);
 }
 #endif
-static inline void nf_reset(struct sk_buff *skb)
-{
-       nf_conntrack_put(skb->nfct);
-       skb->nfct = NULL;
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-       nf_conntrack_put_reasm(skb->nfct_reasm);
-       skb->nfct_reasm = NULL;
-#endif
-}
-
 #ifdef CONFIG_BRIDGE_NETFILTER
 static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
 {
@@ -1373,6 +1350,20 @@ static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge)
                atomic_inc(&nf_bridge->use);
 }
 #endif /* CONFIG_BRIDGE_NETFILTER */
+static inline void nf_reset(struct sk_buff *skb)
+{
+       nf_conntrack_put(skb->nfct);
+       skb->nfct = NULL;
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+       nf_conntrack_put_reasm(skb->nfct_reasm);
+       skb->nfct_reasm = NULL;
+#endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+       nf_bridge_put(skb->nf_bridge);
+       skb->nf_bridge = NULL;
+#endif
+}
+
 #else /* CONFIG_NETFILTER */
 static inline void nf_reset(struct sk_buff *skb) {}
 #endif /* CONFIG_NETFILTER */
index b02dda4..9ab2ddd 100644 (file)
@@ -150,6 +150,7 @@ __KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__
 
 #define        SCM_RIGHTS      0x01            /* rw: access rights (array of int) */
 #define SCM_CREDENTIALS 0x02           /* rw: struct ucred             */
+#define SCM_SECURITY   0x03            /* rw: security label           */
 
 struct ucred {
        __u32   pid;
index d33c6fa..b4acb3d 100644 (file)
@@ -36,7 +36,7 @@ struct svc_sock {
 
        struct list_head        sk_deferred;    /* deferred requests that need to
                                                 * be revisted */
-       struct semaphore        sk_sem;         /* to serialize sending data */
+       struct mutex            sk_mutex;       /* to serialize sending data */
 
        int                     (*sk_recvfrom)(struct svc_rqst *rqstp);
        int                     (*sk_sendto)(struct svc_rqst *rqstp);
index bac61db..76eaeff 100644 (file)
@@ -211,6 +211,7 @@ enum
        NET_SCTP=17,
        NET_LLC=18,
        NET_NETFILTER=19,
+       NET_DCCP=20,
 };
 
 /* /proc/sys/kernel/random */
@@ -261,6 +262,8 @@ enum
        NET_CORE_DEV_WEIGHT=17,
        NET_CORE_SOMAXCONN=18,
        NET_CORE_BUDGET=19,
+       NET_CORE_AEVENT_ETIME=20,
+       NET_CORE_AEVENT_RSEQTH=21,
 };
 
 /* /proc/sys/net/ethernet */
@@ -397,6 +400,9 @@ enum
        NET_TCP_CONG_CONTROL=110,
        NET_TCP_ABC=111,
        NET_IPV4_IPFRAG_MAX_DIST=112,
+       NET_TCP_MTU_PROBING=113,
+       NET_TCP_BASE_MSS=114,
+       NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115,
 };
 
 enum {
@@ -451,6 +457,7 @@ enum
        NET_IPV4_CONF_ARP_ANNOUNCE=18,
        NET_IPV4_CONF_ARP_IGNORE=19,
        NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
+       NET_IPV4_CONF_ARP_ACCEPT=21,
        __NET_IPV4_CONF_MAX
 };
 
@@ -531,6 +538,11 @@ enum {
        NET_IPV6_MAX_DESYNC_FACTOR=15,
        NET_IPV6_MAX_ADDRESSES=16,
        NET_IPV6_FORCE_MLD_VERSION=17,
+       NET_IPV6_ACCEPT_RA_DEFRTR=18,
+       NET_IPV6_ACCEPT_RA_PINFO=19,
+       NET_IPV6_ACCEPT_RA_RTR_PREF=20,
+       NET_IPV6_RTR_PROBE_INTERVAL=21,
+       NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
        __NET_IPV6_MAX
 };
 
@@ -562,6 +574,21 @@ enum {
        __NET_NEIGH_MAX
 };
 
+/* /proc/sys/net/dccp */
+enum {
+       NET_DCCP_DEFAULT=1,
+};
+
+/* /proc/sys/net/dccp/default */
+enum {
+       NET_DCCP_DEFAULT_SEQ_WINDOW  = 1,
+       NET_DCCP_DEFAULT_RX_CCID     = 2,
+       NET_DCCP_DEFAULT_TX_CCID     = 3,
+       NET_DCCP_DEFAULT_ACK_RATIO   = 4,
+       NET_DCCP_DEFAULT_SEND_ACKVEC = 5,
+       NET_DCCP_DEFAULT_SEND_NDP    = 6,
+};
+
 /* /proc/sys/net/ipx */
 enum {
        NET_IPX_PPROP_BROADCASTING=1,
index f2bb239..542d395 100644 (file)
@@ -343,6 +343,12 @@ struct tcp_sock {
                __u32   seq;
                __u32   time;
        } rcvq_space;
+
+/* TCP-specific MTU probe information. */
+       struct {
+               __u32             probe_seq_start;
+               __u32             probe_seq_end;
+       } mtu_probe;
 };
 
 static inline struct tcp_sock *tcp_sk(const struct sock *sk)
index 827cc6d..130d125 100644 (file)
@@ -1018,8 +1018,6 @@ extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
        unsigned char descindex, void *buf, int size);
 extern int usb_get_status(struct usb_device *dev,
        int type, int target, void *data);
-extern int usb_get_string(struct usb_device *dev,
-       unsigned short langid, unsigned char index, void *buf, int size);
 extern int usb_string(struct usb_device *dev, int index,
        char *buf, size_t size);
 
index ff81117..1d78870 100644 (file)
@@ -801,7 +801,9 @@ struct usb_gadget_driver {
  * Call this in your gadget driver's module initialization function,
  * to tell the underlying usb controller driver about your driver.
  * The driver's bind() function will be called to bind it to a
- * gadget.  This function must be called in a context that can sleep.
+ * gadget before this registration call returns.  It's expected that
+ * the bind() functions will be in init sections.
+ * This function must be called in a context that can sleep.
  */
 int usb_gadget_register_driver (struct usb_gadget_driver *driver);
 
@@ -814,7 +816,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver);
  * going away.  If the controller is connected to a USB host,
  * it will first disconnect().  The driver is also requested
  * to unbind() and clean up any device state, before this procedure
- * finally returns.
+ * finally returns.  It's expected that the unbind() functions
+ * will in in exit sections, so may not be linked in some kernels.
  * This function must be called in a context that can sleep.
  */
 int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
index 5208b12..724cfbf 100644 (file)
 #include <linux/time.h> /* need struct timeval */
 #include <linux/poll.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #endif
 #include <linux/compiler.h> /* need __user */
 
 
-#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.15 */
+#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.17 */
 #define HAVE_V4L2 1
 
 /*
 
 #ifdef __KERNEL__
 
+/* Minor device allocation */
+#define MINOR_VFL_TYPE_GRABBER_MIN   0
+#define MINOR_VFL_TYPE_GRABBER_MAX  63
+#define MINOR_VFL_TYPE_RADIO_MIN    64
+#define MINOR_VFL_TYPE_RADIO_MAX   127
+#define MINOR_VFL_TYPE_VTX_MIN     192
+#define MINOR_VFL_TYPE_VTX_MAX     223
+#define MINOR_VFL_TYPE_VBI_MIN     224
+#define MINOR_VFL_TYPE_VBI_MAX     255
+
 #define VFL_TYPE_GRABBER       0
 #define VFL_TYPE_VBI           1
 #define VFL_TYPE_RADIO         2
@@ -80,7 +91,7 @@ struct video_device
 
        /* for videodev.c intenal usage -- please don't touch */
        int users;                     /* video_exclusive_{open|close} ... */
-       struct semaphore lock;         /* ... helper function uses these   */
+       struct mutex lock;             /* ... helper function uses these   */
        char devfs_name[64];           /* devfs */
        struct class_device class_dev; /* sysfs */
 };
@@ -952,13 +963,68 @@ struct v4l2_sliced_vbi_format
        __u32   reserved[2];            /* must be zero */
 };
 
-#define V4L2_SLICED_TELETEXT_B          (0x0001)
-#define V4L2_SLICED_VPS                 (0x0400)
-#define V4L2_SLICED_CAPTION_525         (0x1000)
-#define V4L2_SLICED_WSS_625             (0x4000)
-
-#define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
-#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
+/* Teletext World System Teletext
+   (WST), defined on ITU-R BT.653-2 */
+#define V4L2_SLICED_TELETEXT_PAL_B      (0x000001)
+#define V4L2_SLICED_TELETEXT_PAL_C      (0x000002)
+#define V4L2_SLICED_TELETEXT_NTSC_B     (0x000010)
+#define V4L2_SLICED_TELETEXT_SECAM      (0x000020)
+
+/* Teletext North American Broadcast Teletext Specification
+   (NABTS), defined on ITU-R BT.653-2 */
+#define V4L2_SLICED_TELETEXT_NTSC_C     (0x000040)
+#define V4L2_SLICED_TELETEXT_NTSC_D     (0x000080)
+
+/* Video Program System, defined on ETS 300 231*/
+#define V4L2_SLICED_VPS                 (0x000400)
+
+/* Closed Caption, defined on EIA-608 */
+#define V4L2_SLICED_CAPTION_525         (0x001000)
+#define V4L2_SLICED_CAPTION_625         (0x002000)
+
+/* Wide Screen System, defined on ITU-R BT1119.1 */
+#define V4L2_SLICED_WSS_625             (0x004000)
+
+/* Wide Screen System, defined on IEC 61880 */
+#define V4L2_SLICED_WSS_525             (0x008000)
+
+/* Vertical Interval Timecode (VITC), defined on SMPTE 12M */
+#define V4l2_SLICED_VITC_625           (0x010000)
+#define V4l2_SLICED_VITC_525           (0x020000)
+
+#define V4L2_SLICED_TELETEXT_B         (V4L2_SLICED_TELETEXT_PAL_B  |\
+                                        V4L2_SLICED_TELETEXT_NTSC_B)
+
+#define V4L2_SLICED_TELETEXT           (V4L2_SLICED_TELETEXT_PAL_B  |\
+                                        V4L2_SLICED_TELETEXT_PAL_C  |\
+                                        V4L2_SLICED_TELETEXT_SECAM  |\
+                                        V4L2_SLICED_TELETEXT_NTSC_B |\
+                                        V4L2_SLICED_TELETEXT_NTSC_C |\
+                                        V4L2_SLICED_TELETEXT_NTSC_D)
+
+#define V4L2_SLICED_CAPTION            (V4L2_SLICED_CAPTION_525     |\
+                                        V4L2_SLICED_CAPTION_625)
+
+#define V4L2_SLICED_WSS                        (V4L2_SLICED_WSS_525         |\
+                                        V4L2_SLICED_WSS_625)
+
+#define V4L2_SLICED_VITC               (V4L2_SLICED_VITC_525        |\
+                                        V4L2_SLICED_VITC_625)
+
+#define V4L2_SLICED_VBI_525             (V4L2_SLICED_TELETEXT_NTSC_B |\
+                                        V4L2_SLICED_TELETEXT_NTSC_C |\
+                                        V4L2_SLICED_TELETEXT_NTSC_D |\
+                                        V4L2_SLICED_CAPTION_525     |\
+                                        V4L2_SLICED_WSS_525         |\
+                                        V4l2_SLICED_VITC_525)
+
+#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_PAL_B  |\
+                                        V4L2_SLICED_TELETEXT_PAL_C  |\
+                                        V4L2_SLICED_TELETEXT_SECAM  |\
+                                        V4L2_SLICED_VPS             |\
+                                        V4L2_SLICED_CAPTION_625     |\
+                                        V4L2_SLICED_WSS_625         |\
+                                        V4l2_SLICED_VITC_625)
 
 struct v4l2_sliced_vbi_cap
 {
index 82fbb75..6b42cc4 100644 (file)
@@ -156,6 +156,10 @@ enum {
        XFRM_MSG_FLUSHPOLICY,
 #define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY
 
+       XFRM_MSG_NEWAE,
+#define XFRM_MSG_NEWAE XFRM_MSG_NEWAE
+       XFRM_MSG_GETAE,
+#define XFRM_MSG_GETAE XFRM_MSG_GETAE
        __XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -194,6 +198,21 @@ struct xfrm_encap_tmpl {
        xfrm_address_t  encap_oa;
 };
 
+/* AEVENT flags  */
+enum xfrm_ae_ftype_t {
+       XFRM_AE_UNSPEC,
+       XFRM_AE_RTHR=1, /* replay threshold*/
+       XFRM_AE_RVAL=2, /* replay value */
+       XFRM_AE_LVAL=4, /* lifetime value */
+       XFRM_AE_ETHR=8, /* expiry timer threshold */
+       XFRM_AE_CR=16, /* Event cause is replay update */
+       XFRM_AE_CE=32, /* Event cause is timer expiry */
+       XFRM_AE_CU=64, /* Event cause is policy update */
+       __XFRM_AE_MAX
+
+#define XFRM_AE_MAX (__XFRM_AE_MAX - 1)
+};
+
 /* Netlink message attributes.  */
 enum xfrm_attr_type_t {
        XFRMA_UNSPEC,
@@ -205,6 +224,10 @@ enum xfrm_attr_type_t {
        XFRMA_SA,
        XFRMA_POLICY,
        XFRMA_SEC_CTX,          /* struct xfrm_sec_ctx */
+       XFRMA_LTIME_VAL,
+       XFRMA_REPLAY_VAL,
+       XFRMA_REPLAY_THRESH,
+       XFRMA_ETIMER_THRESH,
        __XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -235,6 +258,11 @@ struct xfrm_usersa_id {
        __u8                            proto;
 };
 
+struct xfrm_aevent_id {
+       struct xfrm_usersa_id           sa_id;
+       __u32                           flags;
+};
+
 struct xfrm_userspi_info {
        struct xfrm_usersa_info         info;
        __u32                           min;
@@ -306,6 +334,8 @@ enum xfrm_nlgroups {
 #define XFRMNLGRP_SA           XFRMNLGRP_SA
        XFRMNLGRP_POLICY,
 #define XFRMNLGRP_POLICY       XFRMNLGRP_POLICY
+       XFRMNLGRP_AEVENTS,
+#define XFRMNLGRP_AEVENTS      XFRMNLGRP_AEVENTS
        __XFRMNLGRP_MAX
 };
 #define XFRMNLGRP_MAX  (__XFRMNLGRP_MAX - 1)
index ad3e9bb..302d5b3 100644 (file)
@@ -47,13 +47,6 @@ struct ir_input_state {
        int                keypressed;  /* current state */
 };
 
-extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
-
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
                   int ir_type, IR_KEYTAB_TYPE *ir_codes);
 void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir);
@@ -64,6 +57,39 @@ int  ir_dump_samples(u32 *samples, int count);
 int  ir_decode_biphase(u32 *samples, int count, int low, int high);
 int  ir_decode_pulsedistance(u32 *samples, int count, int low, int high);
 
+/* Keymaps to be used by other modules */
+
+extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_eztv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_videomate_tv_pvr[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+
 #endif
 
 /*
index 2bc634f..fee579f 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/i2c.h>         /* for i2c subsystem */
 #include <asm/io.h>            /* for accessing devices */
 #include <linux/stringify.h>
+#include <linux/mutex.h>
+
 #include <linux/vmalloc.h>     /* for vmalloc() */
 #include <linux/mm.h>          /* for vmalloc_to_page() */
 
@@ -112,7 +114,7 @@ struct saa7146_dev
 
        /* different device locks */
        spinlock_t                      slock;
-       struct semaphore                lock;
+       struct mutex                    lock;
 
        unsigned char                   __iomem *mem;           /* pointer to mapped IO memory */
        int                             revision;       /* chip revision; needed for bug-workarounds*/
@@ -133,15 +135,16 @@ struct saa7146_dev
        void (*vv_callback)(struct saa7146_dev *dev, unsigned long status);
 
        /* i2c-stuff */
-       struct semaphore        i2c_lock;
-       u32                     i2c_bitrate;
-       struct saa7146_dma      d_i2c;  /* pointer to i2c memory */
-       wait_queue_head_t       i2c_wq;
-       int                     i2c_op;
+       struct mutex                    i2c_lock;
+
+       u32                             i2c_bitrate;
+       struct saa7146_dma              d_i2c;  /* pointer to i2c memory */
+       wait_queue_head_t               i2c_wq;
+       int                             i2c_op;
 
        /* memories */
-       struct saa7146_dma      d_rps0;
-       struct saa7146_dma      d_rps1;
+       struct saa7146_dma              d_rps0;
+       struct saa7146_dma              d_rps1;
 };
 
 /* from saa7146_i2c.c */
@@ -150,7 +153,7 @@ int saa7146_i2c_transfer(struct saa7146_dev *saa, const struct i2c_msg *msgs, in
 
 /* from saa7146_core.c */
 extern struct list_head saa7146_devices;
-extern struct semaphore saa7146_devices_lock;
+extern struct mutex saa7146_devices_lock;
 int saa7146_register_extension(struct saa7146_extension*);
 int saa7146_unregister_extension(struct saa7146_extension*);
 struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc);
index 15821ab..ad9c171 100644 (file)
@@ -14,6 +14,7 @@ enum param_type {
 
 struct tuner_range {
        unsigned short limit;
+       unsigned char config;
        unsigned char cb;
 };
 
@@ -38,7 +39,6 @@ struct tuner_params {
         * static unless the control byte was sent first.
         */
        unsigned int cb_first_if_lower_freq:1;
-       unsigned char config; /* to be moved into struct tuner_range for dvb-pll merge */
 
        unsigned int count;
        struct tuner_range *ranges;
@@ -46,6 +46,7 @@ struct tuner_params {
 
 struct tunertype {
        char *name;
+       unsigned int count;
        struct tuner_params *params;
 };
 
index a5beeac..017fed7 100644 (file)
 
 #define TUNER_LG_TDVS_H062F            64      /* DViCO FusionHDTV 5 */
 #define TUNER_YMEC_TVF66T5_B_DFF       65      /* Acorp Y878F */
-#define TUNER_LG_NTSC_TALN_MINI                66
+#define TUNER_LG_TALN                  66
 #define TUNER_PHILIPS_TD1316           67
 
 #define TUNER_PHILIPS_TUV1236D         68      /* ATI HDTV Wonder */
 #define TUNER_TNF_5335MF                69     /* Sabrent Bt848   */
 #define TUNER_SAMSUNG_TCPN_2121P30A     70     /* Hauppauge PVR-500MCE NTSC */
+#define TUNER_XCEIVE_XC3028            71
+
+#define TUNER_THOMSON_FE6600           72      /* DViCO FusionHDTV DVB-T Hybrid */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
@@ -209,6 +212,7 @@ struct tuner {
 extern unsigned const int tuner_count;
 
 extern int microtune_init(struct i2c_client *c);
+extern int xc3028_init(struct i2c_client *c);
 extern int tda8290_init(struct i2c_client *c);
 extern int tda8290_probe(struct i2c_client *c);
 extern int tea5767_tuner_init(struct i2c_client *c);
index d4030a7..2360453 100644 (file)
@@ -58,6 +58,9 @@
 /* Prints the ioctl in a human-readable format */
 extern void v4l_printk_ioctl(unsigned int cmd);
 
+/* Prints the ioctl and arg in a human-readable format */
+extern void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg);
+
 /* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */
 #define v4l_print_ioctl(name, cmd)              \
        do {                                     \
@@ -100,6 +103,7 @@ enum v4l2_chip_ident {
        V4L2_IDENT_UNKNOWN = 0,
 
        /* module saa7115: reserved range 100-149 */
+       V4L2_IDENT_SAA7113 = 103,
        V4L2_IDENT_SAA7114 = 104,
        V4L2_IDENT_SAA7115 = 105,
 
@@ -115,12 +119,15 @@ enum v4l2_chip_ident {
 };
 
 /* audio ioctls */
-/* v4l device was opened in Radio mode */
+
+/* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */
 #define AUDC_SET_RADIO        _IO('d',88)
-/* select from TV,radio,extern,MUTE */
+
+/* select from TV,radio,extern,MUTE, to be replaced with VIDIOC_INT_S_AUDIO_ROUTING */
 #define AUDC_SET_INPUT        _IOW('d',89,int)
 
-/* msp3400 ioctl: will be removed in the near future */
+/* msp3400 ioctl: will be removed in the near future, to be replaced by
+   VIDIOC_INT_S_AUDIO_ROUTING. */
 struct msp_matrix {
   int input;
   int output;
@@ -128,12 +135,25 @@ struct msp_matrix {
 #define MSP_SET_MATRIX     _IOW('m',17,struct msp_matrix)
 
 /* tuner ioctls */
+
 /* Sets tuner type and its I2C addr */
-#define TUNER_SET_TYPE_ADDR          _IOW('d',90,int)
-/* Puts tuner on powersaving state, disabling it, except for i2c */
-#define TUNER_SET_STANDBY            _IOW('d',91,int)
+#define TUNER_SET_TYPE_ADDR          _IOW('d', 90, int)
+
+/* Puts tuner on powersaving state, disabling it, except for i2c. To be replaced
+   by VIDIOC_INT_S_STANDBY. */
+#define TUNER_SET_STANDBY            _IOW('d', 91, int)
+
 /* Sets tda9887 specific stuff, like port1, port2 and qss */
-#define TDA9887_SET_CONFIG           _IOW('d',92,int)
+#define TDA9887_SET_CONFIG           _IOW('d', 92, int)
+
+/* Switch the tuner to a specific tuner mode. Replacement of AUDC_SET_RADIO */
+#define VIDIOC_INT_S_TUNER_MODE             _IOW('d', 93, enum v4l2_tuner_type)
+
+/* Generic standby command. Passing -1 (all bits set to 1) will put the whole
+   chip into standby mode, value 0 will make the chip fully active. Specific
+   bits can be used by certain chips to enable/disable specific subsystems.
+   Replacement of TUNER_SET_STANDBY. */
+#define VIDIOC_INT_S_STANDBY        _IOW('d', 94, u32)
 
 /* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
 #define        VIDIOC_INT_S_REGISTER           _IOR ('d', 100, struct v4l2_register)
@@ -160,7 +180,8 @@ struct msp_matrix {
 
 /* Used to generate VBI signals on a video signal. v4l2_sliced_vbi_data is
    filled with the data packets that should be output. Note that if you set
-   the line field to 0, then that VBI signal is disabled. */
+   the line field to 0, then that VBI signal is disabled. If no
+   valid VBI data was found, then the type field is set to 0 on return. */
 #define VIDIOC_INT_S_VBI_DATA          _IOW ('d', 105, struct v4l2_sliced_vbi_data)
 
 /* Used to obtain the sliced VBI packet from a readback register. Not all
@@ -168,11 +189,11 @@ struct msp_matrix {
    register contains invalid or erroneous data -EIO is returned. Note that
    you must fill in the 'id' member and the 'field' member (to determine
    whether CC data from the first or second field should be obtained). */
-#define VIDIOC_INT_G_VBI_DATA          _IOWR('d', 106, struct v4l2_sliced_vbi_data *)
+#define VIDIOC_INT_G_VBI_DATA          _IOWR('d', 106, struct v4l2_sliced_vbi_data)
 
 /* Returns the chip identifier or V4L2_IDENT_UNKNOWN if no identification can
    be made. */
-#define VIDIOC_INT_G_CHIP_IDENT                _IOR ('d', 107, enum v4l2_chip_ident *)
+#define VIDIOC_INT_G_CHIP_IDENT                _IOR ('d', 107, enum v4l2_chip_ident)
 
 /* Sets I2S speed in bps. This is used to provide a standard way to select I2S
    clock used by driving digital audio streams at some board designs.
@@ -180,4 +201,25 @@ struct msp_matrix {
    If the frequency is not supported, then -EINVAL is returned. */
 #define VIDIOC_INT_I2S_CLOCK_FREQ      _IOW ('d', 108, u32)
 
+/* Routing definition, device dependent. It specifies which inputs (if any)
+   should be routed to which outputs (if any). */
+struct v4l2_routing {
+       u32 input;
+       u32 output;
+};
+
+/* These internal commands should be used to define the inputs and outputs
+   of an audio/video chip. They will replace AUDC_SET_INPUT.
+   The v4l2 API commands VIDIOC_S/G_INPUT, VIDIOC_S/G_OUTPUT,
+   VIDIOC_S/G_AUDIO and VIDIOC_S/G_AUDOUT are meant to be used by the
+   user. Internally these commands should be used to switch inputs/outputs
+   because only the driver knows how to map a 'Television' input to the precise
+   input/output routing of an A/D converter, or a DSP, or a video digitizer.
+   These four commands should only be sent directly to an i2c device, they
+   should not be broadcast as the routing is very device specific. */
+#define        VIDIOC_INT_S_AUDIO_ROUTING      _IOW ('d', 109, struct v4l2_routing)
+#define        VIDIOC_INT_G_AUDIO_ROUTING      _IOR ('d', 110, struct v4l2_routing)
+#define        VIDIOC_INT_S_VIDEO_ROUTING      _IOW ('d', 111, struct v4l2_routing)
+#define        VIDIOC_INT_G_VIDEO_ROUTING      _IOR ('d', 112, struct v4l2_routing)
+
 #endif /* V4L2_COMMON_H_ */
index ad0a07a..b78d90f 100644 (file)
@@ -11,7 +11,7 @@ struct videobuf_dvb {
        struct videobuf_queue      dvbq;
 
        /* video-buf-dvb state info */
-       struct semaphore           lock;
+       struct mutex               lock;
        struct task_struct         *thread;
        int                        nfeeds;
 
index 8ecfd78..d90dec5 100644 (file)
@@ -177,7 +177,7 @@ struct videobuf_queue_ops {
 };
 
 struct videobuf_queue {
-       struct semaphore           lock;
+       struct mutex               lock;
        spinlock_t                 *irqlock;
        struct pci_dev             *pci;
 
index bfc1779..427dac9 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <linux/socket.h>
 #include <linux/un.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 
 extern void unix_inflight(struct file *fp);
@@ -71,7 +72,7 @@ struct unix_sock {
         struct unix_address     *addr;
         struct dentry          *dentry;
         struct vfsmount                *mnt;
-        struct semaphore        readsem;
+       struct mutex            readlock;
         struct sock            *peer;
         struct sock            *other;
         struct sock            *gc_tree;
index a4b6168..465b783 100644 (file)
@@ -6,10 +6,8 @@
 #include <net/tcp.h>
 #include <asm/byteorder.h>
 
-typedef unsigned short dn_address;
-
-#define dn_ntohs(x) le16_to_cpu((unsigned short)(x))
-#define dn_htons(x) cpu_to_le16((unsigned short)(x))
+#define dn_ntohs(x) le16_to_cpu(x)
+#define dn_htons(x) cpu_to_le16(x)
 
 struct dn_scp                                   /* Session Control Port */
 {
@@ -31,36 +29,36 @@ struct dn_scp                                   /* Session Control Port */
 #define DN_CL    15                     /* Closed               */
 #define DN_CN    16                     /* Closed Notification  */
 
-        unsigned short          addrloc;
-        unsigned short          addrrem;
-        unsigned short          numdat;
-        unsigned short          numoth;
-        unsigned short          numoth_rcv;
-        unsigned short          numdat_rcv;
-        unsigned short          ackxmt_dat;
-        unsigned short          ackxmt_oth;
-        unsigned short          ackrcv_dat;
-        unsigned short          ackrcv_oth;
-        unsigned char           flowrem_sw;
-       unsigned char           flowloc_sw;
+        __le16          addrloc;
+        __le16          addrrem;
+        __u16          numdat;
+        __u16          numoth;
+        __u16          numoth_rcv;
+        __u16          numdat_rcv;
+        __u16          ackxmt_dat;
+        __u16          ackxmt_oth;
+        __u16          ackrcv_dat;
+        __u16          ackrcv_oth;
+        __u8           flowrem_sw;
+       __u8           flowloc_sw;
 #define DN_SEND         2
 #define DN_DONTSEND     1
 #define DN_NOCHANGE     0
-       unsigned short          flowrem_dat;
-       unsigned short          flowrem_oth;
-       unsigned short          flowloc_dat;
-       unsigned short          flowloc_oth;
-       unsigned char           services_rem;
-       unsigned char           services_loc;
-       unsigned char           info_rem;
-       unsigned char           info_loc;
-
-       unsigned short          segsize_rem;
-       unsigned short          segsize_loc;
-
-       unsigned char           nonagle;
-       unsigned char           multi_ireq;
-       unsigned char           accept_mode;
+       __u16           flowrem_dat;
+       __u16           flowrem_oth;
+       __u16           flowloc_dat;
+       __u16           flowloc_oth;
+       __u8            services_rem;
+       __u8            services_loc;
+       __u8            info_rem;
+       __u8            info_loc;
+
+       __u16           segsize_rem;
+       __u16           segsize_loc;
+
+       __u8            nonagle;
+       __u8            multi_ireq;
+       __u8            accept_mode;
        unsigned long           seg_total; /* Running total of current segment */
 
        struct optdata_dn     conndata_in;
@@ -160,40 +158,41 @@ static inline struct dn_scp *DN_SK(struct sock *sk)
  */
 #define DN_SKB_CB(skb) ((struct dn_skb_cb *)(skb)->cb)
 struct dn_skb_cb {
-       unsigned short dst;
-       unsigned short src;
-       unsigned short hops;
-       unsigned short dst_port;
-       unsigned short src_port;
-       unsigned char services;
-       unsigned char info;
-       unsigned char rt_flags;
-       unsigned char nsp_flags;
-       unsigned short segsize;
-       unsigned short segnum;
-       unsigned short xmit_count;
+       __le16 dst;
+       __le16 src;
+       __u16 hops;
+       __le16 dst_port;
+       __le16 src_port;
+       __u8 services;
+       __u8 info;
+       __u8 rt_flags;
+       __u8 nsp_flags;
+       __u16 segsize;
+       __u16 segnum;
+       __u16 xmit_count;
        unsigned long stamp;
        int iif;
 };
 
-static inline dn_address dn_eth2dn(unsigned char *ethaddr)
+static inline __le16 dn_eth2dn(unsigned char *ethaddr)
 {
-       return ethaddr[4] | (ethaddr[5] << 8);
+       return dn_htons(ethaddr[4] | (ethaddr[5] << 8));
 }
 
-static inline dn_address dn_saddr2dn(struct sockaddr_dn *saddr)
+static inline __le16 dn_saddr2dn(struct sockaddr_dn *saddr)
 {
-       return *(dn_address *)saddr->sdn_nodeaddr;
+       return *(__le16 *)saddr->sdn_nodeaddr;
 }
 
-static inline void dn_dn2eth(unsigned char *ethaddr, dn_address addr)
+static inline void dn_dn2eth(unsigned char *ethaddr, __le16 addr)
 {
+       __u16 a = dn_ntohs(addr);
        ethaddr[0] = 0xAA;
        ethaddr[1] = 0x00;
        ethaddr[2] = 0x04;
        ethaddr[3] = 0x00;
-       ethaddr[4] = (unsigned char)(addr & 0xff);
-       ethaddr[5] = (unsigned char)(addr >> 8);
+       ethaddr[4] = (__u8)(a & 0xff);
+       ethaddr[5] = (__u8)(a >> 8);
 }
 
 static inline void dn_sk_ports_copy(struct flowi *fl, struct dn_scp *scp)
@@ -202,7 +201,7 @@ static inline void dn_sk_ports_copy(struct flowi *fl, struct dn_scp *scp)
        fl->uli_u.dnports.dport = scp->addrrem;
        fl->uli_u.dnports.objnum = scp->addr.sdn_objnum;
        if (fl->uli_u.dnports.objnum == 0) {
-               fl->uli_u.dnports.objnamel = scp->addr.sdn_objnamel;
+               fl->uli_u.dnports.objnamel = (__u8)dn_ntohs(scp->addr.sdn_objnamel);
                memcpy(fl->uli_u.dnports.objname, scp->addr.sdn_objname, 16);
        }
 }
@@ -217,7 +216,7 @@ extern unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu);
 extern struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr);
 extern struct sock *dn_find_by_skb(struct sk_buff *skb);
 #define DN_ASCBUF_LEN 9
-extern char *dn_addr2asc(dn_address, char *);
+extern char *dn_addr2asc(__u16, char *);
 extern int dn_destroy_timer(struct sock *sk);
 
 extern int dn_sockaddr2username(struct sockaddr_dn *addr, unsigned char *buf, unsigned char type);
@@ -226,7 +225,7 @@ extern int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn
 extern void dn_start_slow_timer(struct sock *sk);
 extern void dn_stop_slow_timer(struct sock *sk);
 
-extern dn_address decnet_address;
+extern __le16 decnet_address;
 extern int decnet_debug_level;
 extern int decnet_time_wait;
 extern int decnet_dn_count;
index 5a86e78..cee4682 100644 (file)
@@ -7,11 +7,11 @@ struct dn_dev;
 struct dn_ifaddr {
        struct dn_ifaddr *ifa_next;
        struct dn_dev    *ifa_dev;
-       dn_address       ifa_local;
-       dn_address       ifa_address;
-       unsigned char    ifa_flags;
-       unsigned char    ifa_scope;
-       char             ifa_label[IFNAMSIZ];
+       __le16            ifa_local;
+       __le16            ifa_address;
+       __u8              ifa_flags;
+       __u8              ifa_scope;
+       char              ifa_label[IFNAMSIZ];
 };
 
 #define DN_DEV_S_RU  0 /* Run - working normally   */
@@ -91,7 +91,7 @@ struct dn_dev {
        struct timer_list timer;
        unsigned long t3;
        struct neigh_parms *neigh_parms;
-       unsigned char addr[ETH_ALEN];
+       __u8 addr[ETH_ALEN];
        struct neighbour *router; /* Default router on circuit */
        struct neighbour *peer;   /* Peer on pointopoint links */
        unsigned long uptime;     /* Time device went up in jiffies */
@@ -99,56 +99,56 @@ struct dn_dev {
 
 struct dn_short_packet
 {
-       unsigned char   msgflg;
-       unsigned short  dstnode;
-       unsigned short  srcnode;
-       unsigned char   forward;
+       __u8    msgflg;
+       __le16 dstnode;
+       __le16 srcnode;
+       __u8   forward;
 } __attribute__((packed));
 
 struct dn_long_packet
 {
-       unsigned char   msgflg;
-       unsigned char   d_area;
-       unsigned char   d_subarea;
-       unsigned char   d_id[6];
-       unsigned char   s_area;
-       unsigned char   s_subarea;
-       unsigned char   s_id[6];
-       unsigned char   nl2;
-       unsigned char   visit_ct;
-       unsigned char   s_class;
-       unsigned char   pt;
+       __u8   msgflg;
+       __u8   d_area;
+       __u8   d_subarea;
+       __u8   d_id[6];
+       __u8   s_area;
+       __u8   s_subarea;
+       __u8   s_id[6];
+       __u8   nl2;
+       __u8   visit_ct;
+       __u8   s_class;
+       __u8   pt;
 } __attribute__((packed));
 
 /*------------------------- DRP - Routing messages ---------------------*/
 
 struct endnode_hello_message
 {
-       unsigned char   msgflg;
-       unsigned char   tiver[3];
-       unsigned char   id[6];
-       unsigned char   iinfo;
-       unsigned short  blksize;
-       unsigned char   area;
-       unsigned char   seed[8];
-       unsigned char   neighbor[6];
-       unsigned short  timer;
-       unsigned char   mpd;
-       unsigned char   datalen;
-       unsigned char   data[2];
+       __u8   msgflg;
+       __u8   tiver[3];
+       __u8   id[6];
+       __u8   iinfo;
+       __le16 blksize;
+       __u8   area;
+       __u8   seed[8];
+       __u8   neighbor[6];
+       __le16 timer;
+       __u8   mpd;
+       __u8   datalen;
+       __u8   data[2];
 } __attribute__((packed));
 
 struct rtnode_hello_message
 {
-       unsigned char   msgflg;
-       unsigned char   tiver[3];
-       unsigned char   id[6];
-       unsigned char   iinfo;
-       unsigned short  blksize;
-       unsigned char   priority;
-       unsigned char   area;
-       unsigned short  timer;
-       unsigned char   mpd;
+       __u8   msgflg;
+       __u8   tiver[3];
+       __u8   id[6];
+       __u8   iinfo;
+       __le16  blksize;
+       __u8   priority;
+       __u8   area;
+       __le16  timer;
+       __u8   mpd;
 } __attribute__((packed));
 
 
@@ -169,12 +169,12 @@ extern void dn_dev_down(struct net_device *);
 
 extern int dn_dev_set_default(struct net_device *dev, int force);
 extern struct net_device *dn_dev_get_default(void);
-extern int dn_dev_bind_default(dn_address *addr);
+extern int dn_dev_bind_default(__le16 *addr);
 
 extern int register_dnaddr_notifier(struct notifier_block *nb);
 extern int unregister_dnaddr_notifier(struct notifier_block *nb);
 
-static inline int dn_dev_islocal(struct net_device *dev, dn_address addr)
+static inline int dn_dev_islocal(struct net_device *dev, __le16 addr)
 {
        struct dn_dev *dn_db = dev->dn_ptr;
        struct dn_ifaddr *ifa;
index cd3c96d..a15dcf0 100644 (file)
@@ -37,7 +37,7 @@ struct dn_fib_nh {
        int                     nh_weight;
        int                     nh_power;
        int                     nh_oif;
-       u32                     nh_gw;
+       __le16                  nh_gw;
 };
 
 struct dn_fib_info {
@@ -48,7 +48,7 @@ struct dn_fib_info {
        int                     fib_dead;
        unsigned                fib_flags;
        int                     fib_protocol;
-       dn_address              fib_prefsrc;
+       __le16                  fib_prefsrc;
        __u32                   fib_priority;
        __u32                   fib_metrics[RTAX_MAX];
 #define dn_fib_mtu  fib_metrics[RTAX_MTU-1]
@@ -71,15 +71,15 @@ struct dn_fib_info {
 #define DN_FIB_RES_OIF(res)    (DN_FIB_RES_NH(res).nh_oif)
 
 typedef struct {
-       u16     datum;
+       __le16  datum;
 } dn_fib_key_t;
 
 typedef struct {
-       u16     datum;
+       __le16  datum;
 } dn_fib_hash_t;
 
 typedef struct {
-       u16     datum;
+       __u16   datum;
 } dn_fib_idx_t;
 
 struct dn_fib_node {
@@ -126,11 +126,11 @@ extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi,
                        const struct flowi *fl,
                        struct dn_fib_res *res);
 extern void dn_fib_release_info(struct dn_fib_info *fi);
-extern u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type);
+extern __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type);
 extern void dn_fib_flush(void);
 extern void dn_fib_select_multipath(const struct flowi *fl,
                                        struct dn_fib_res *res);
-extern int dn_fib_sync_down(dn_address local, struct net_device *dev, 
+extern int dn_fib_sync_down(__le16 local, struct net_device *dev,
                                int force);
 extern int dn_fib_sync_up(struct net_device *dev);
 
@@ -148,8 +148,8 @@ extern void dn_fib_table_cleanup(void);
 extern void dn_fib_rules_init(void);
 extern void dn_fib_rules_cleanup(void);
 extern void dn_fib_rule_put(struct dn_fib_rule *);
-extern __u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags);
-extern unsigned dnet_addr_type(__u16 addr);
+extern __le16 dn_fib_rules_policy(__le16 saddr, struct dn_fib_res *res, unsigned *flags);
+extern unsigned dnet_addr_type(__le16 addr);
 extern int dn_fib_lookup(const struct flowi *fl, struct dn_fib_res *res);
 
 /*
@@ -194,10 +194,10 @@ extern struct dn_fib_table *dn_fib_tables[];
 
 #endif /* CONFIG_DECNET_ROUTER */
 
-static inline u16 dnet_make_mask(int n)
+static inline __le16 dnet_make_mask(int n)
 {
         if (n)
-                return htons(~((1<<(16-n))-1));
+                return dn_htons(~((1<<(16-n))-1));
         return 0;
 }
 
index 4b1eb03..4cb4ae7 100644 (file)
@@ -7,13 +7,13 @@
  */
 struct dn_neigh {
         struct neighbour n;
-       dn_address addr;
+       __le16 addr;
         unsigned long flags;
 #define DN_NDFLAG_R1    0x0001 /* Router L1      */
 #define DN_NDFLAG_R2    0x0002 /* Router L2      */
 #define DN_NDFLAG_P3    0x0004 /* Phase III Node */
         unsigned long blksize;
-       unsigned char priority;
+       __u8 priority;
 };
 
 extern void dn_neigh_init(void);
index e6182b8..96e816b 100644 (file)
@@ -72,77 +72,77 @@ extern struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int nobl
 
 struct nsp_data_seg_msg
 {
-       unsigned char   msgflg;
-       unsigned short  dstaddr;
-       unsigned short  srcaddr;
+       __u8   msgflg;
+       __le16 dstaddr;
+       __le16 srcaddr;
 } __attribute__((packed));
 
 struct nsp_data_opt_msg
 {
-       unsigned short  acknum;
-       unsigned short  segnum;
-       unsigned short  lsflgs;
+       __le16 acknum;
+       __le16 segnum;
+       __le16 lsflgs;
 } __attribute__((packed));
 
 struct nsp_data_opt_msg1
 {
-       unsigned short  acknum;
-       unsigned short  segnum;
+       __le16 acknum;
+       __le16 segnum;
 } __attribute__((packed));
 
 
 /* Acknowledgment Message (data/other data)                             */
 struct nsp_data_ack_msg
 {
-       unsigned char   msgflg;
-       unsigned short  dstaddr;
-       unsigned short  srcaddr;
-       unsigned short  acknum;
+       __u8   msgflg;
+       __le16 dstaddr;
+       __le16 srcaddr;
+       __le16 acknum;
 } __attribute__((packed));
 
 /* Connect Acknowledgment Message */
 struct  nsp_conn_ack_msg
 {
-       unsigned char   msgflg;
-       unsigned short  dstaddr;
+       __u8 msgflg;
+       __le16 dstaddr;
 } __attribute__((packed));
 
 
 /* Connect Initiate/Retransmit Initiate/Connect Confirm */
 struct  nsp_conn_init_msg
 {
-       unsigned char   msgflg;
+       __u8   msgflg;
 #define NSP_CI      0x18            /* Connect Initiate     */
 #define NSP_RCI     0x68            /* Retrans. Conn Init   */
-       unsigned short  dstaddr;
-       unsigned short  srcaddr;
-       unsigned char   services;
+       __le16 dstaddr;
+       __le16 srcaddr;
+       __u8   services;
 #define NSP_FC_NONE   0x00            /* Flow Control None    */
 #define NSP_FC_SRC    0x04            /* Seg Req. Count       */
 #define NSP_FC_SCMC   0x08            /* Sess. Control Mess   */
 #define NSP_FC_MASK   0x0c            /* FC type mask         */
-       unsigned char   info;
-       unsigned short  segsize;
+       __u8   info;
+       __le16 segsize;
 } __attribute__((packed));
 
 /* Disconnect Initiate/Disconnect Confirm */
 struct  nsp_disconn_init_msg
 {
-       unsigned char   msgflg;
-       unsigned short  dstaddr;
-       unsigned short  srcaddr;
-       unsigned short  reason;
+       __u8   msgflg;
+       __le16 dstaddr;
+       __le16 srcaddr;
+       __le16 reason;
 } __attribute__((packed));
 
 
 
 struct  srcobj_fmt
 {
-       char            format;
-       unsigned char   task;
-       unsigned short  grpcode;
-       unsigned short  usrcode;
-       char            dlen;
+       __u8   format;
+       __u8   task;
+       __le16 grpcode;
+       __le16 usrcode;
+       __u8   dlen;
 } __attribute__((packed));
 
 /*
@@ -150,7 +150,7 @@ struct  srcobj_fmt
  * numbers used in NSP. Similar in operation to the functions
  * of the same name in TCP.
  */
-static __inline__ int dn_before(unsigned short seq1, unsigned short seq2)
+static __inline__ int dn_before(__u16 seq1, __u16 seq2)
 {
         seq1 &= 0x0fff;
         seq2 &= 0x0fff;
@@ -159,7 +159,7 @@ static __inline__ int dn_before(unsigned short seq1, unsigned short seq2)
 }
 
 
-static __inline__ int dn_after(unsigned short seq1, unsigned short seq2)
+static __inline__ int dn_after(__u16 seq1, __u16 seq2)
 {
         seq1 &= 0x0fff;
         seq2 &= 0x0fff;
@@ -167,23 +167,23 @@ static __inline__ int dn_after(unsigned short seq1, unsigned short seq2)
         return (int)((seq2 - seq1) & 0x0fff) > 2048;
 }
 
-static __inline__ int dn_equal(unsigned short seq1, unsigned short seq2)
+static __inline__ int dn_equal(__u16 seq1, __u16 seq2)
 {
         return ((seq1 ^ seq2) & 0x0fff) == 0;
 }
 
-static __inline__ int dn_before_or_equal(unsigned short seq1, unsigned short seq2)
+static __inline__ int dn_before_or_equal(__u16 seq1, __u16 seq2)
 {
        return (dn_before(seq1, seq2) || dn_equal(seq1, seq2));
 }
 
-static __inline__ void seq_add(unsigned short *seq, unsigned short off)
+static __inline__ void seq_add(__u16 *seq, __u16 off)
 {
         (*seq) += off;
         (*seq) &= 0x0fff;
 }
 
-static __inline__ int seq_next(unsigned short seq1, unsigned short seq2)
+static __inline__ int seq_next(__u16 seq1, __u16 seq2)
 {
        return dn_equal(seq1 + 1, seq2);
 }
@@ -191,7 +191,7 @@ static __inline__ int seq_next(unsigned short seq1, unsigned short seq2)
 /*
  * Can we delay the ack ?
  */
-static __inline__ int sendack(unsigned short seq)
+static __inline__ int sendack(__u16 seq)
 {
         return (int)((seq & 0x1000) ? 0 : 1);
 }
index 5122da3..76f957e 100644 (file)
@@ -71,12 +71,12 @@ struct dn_route {
                struct dn_route *rt_next;
        } u;
 
-       __u16 rt_saddr;
-       __u16 rt_daddr;
-       __u16 rt_gateway;
-       __u16 rt_local_src;     /* Source used for forwarding packets */
-       __u16 rt_src_map;
-       __u16 rt_dst_map;
+       __le16 rt_saddr;
+       __le16 rt_daddr;
+       __le16 rt_gateway;
+       __le16 rt_local_src;    /* Source used for forwarding packets */
+       __le16 rt_src_map;
+       __le16 rt_dst_map;
 
        unsigned rt_flags;
        unsigned rt_type;
index ec7eb86..04d89f7 100644 (file)
@@ -30,8 +30,8 @@ struct flowi {
                } ip6_u;
 
                struct {
-                       __u16                   daddr;
-                       __u16                   saddr;
+                       __le16                  daddr;
+                       __le16                  saddr;
                        __u32                   fwmark;
                        __u8                    scope;
                } dn_u;
@@ -64,8 +64,8 @@ struct flowi {
                } icmpt;
 
                struct {
-                       __u16   sport;
-                       __u16   dport;
+                       __le16  sport;
+                       __le16  dport;
                        __u8    objnum;
                        __u8    objnamel; /* Not 16 bits since max val is 16 */
                        __u8    objname[16]; /* Not zero terminated */
index eb8afe3..e459e1a 100644 (file)
@@ -180,11 +180,8 @@ struct inet6_dev
 
 #ifdef CONFIG_IPV6_PRIVACY
        u8                      rndid[8];
-       u8                      entropy[8];
        struct timer_list       regen_timer;
        struct inet6_ifaddr     *tempaddr_list;
-       __u8                    work_eui64[8];
-       __u8                    work_digest[16];
 #endif
 
        struct neigh_parms      *nd_parms;
index fa587c9..9bf73fe 100644 (file)
@@ -50,6 +50,12 @@ struct inet_connection_sock_af_ops {
                                  char __user *optval, int optlen);
        int         (*getsockopt)(struct sock *sk, int level, int optname, 
                                  char __user *optval, int __user *optlen);
+       int         (*compat_setsockopt)(struct sock *sk,
+                               int level, int optname,
+                               char __user *optval, int optlen);
+       int         (*compat_getsockopt)(struct sock *sk,
+                               int level, int optname,
+                               char __user *optval, int __user *optlen);
        void        (*addr2sockaddr)(struct sock *sk, struct sockaddr *);
        int sockaddr_len;
 };
@@ -72,6 +78,7 @@ struct inet_connection_sock_af_ops {
  * @icsk_probes_out:      unanswered 0 window probes
  * @icsk_ext_hdr_len:     Network protocol overhead (IP/IPv6 options)
  * @icsk_ack:             Delayed ACK control data
+ * @icsk_mtup;            MTU probing control data
  */
 struct inet_connection_sock {
        /* inet_sock has to be the first member! */
@@ -104,6 +111,16 @@ struct inet_connection_sock {
                __u16             last_seg_size; /* Size of last incoming segment          */
                __u16             rcv_mss;       /* MSS used for delayed ACK decisions     */ 
        } icsk_ack;
+       struct {
+               int               enabled;
+
+               /* Range of MTUs to search */
+               int               search_high;
+               int               search_low;
+
+               /* Information on the current probe. */
+               int               probe_size;
+       } icsk_mtup;
        u32                       icsk_ca_priv[16];
 #define ICSK_CA_PRIV_SIZE      (16 * sizeof(u32))
 };
@@ -310,4 +327,13 @@ extern void inet_csk_listen_stop(struct sock *sk);
 
 extern void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr);
 
+extern int inet_csk_ctl_sock_create(struct socket **sock,
+                                   unsigned short family,
+                                   unsigned short type,
+                                   unsigned char protocol);
+
+extern int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname,
+                                     char __user *optval, int __user *optlen);
+extern int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
+                                     char __user *optval, int optlen);
 #endif /* _INET_CONNECTION_SOCK_H */
index fab3d5b..8fe6156 100644 (file)
@@ -356,6 +356,10 @@ extern void        ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
 extern int     ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc);
 extern int     ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen);
 extern int     ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen);
+extern int     compat_ip_setsockopt(struct sock *sk, int level,
+                       int optname, char __user *optval, int optlen);
+extern int     compat_ip_getsockopt(struct sock *sk, int level,
+                       int optname, char __user *optval, int __user *optlen);
 extern int     ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *));
 
 extern int     ip_recv_error(struct sock *sk, struct msghdr *msg, int len);
index 1f2e428..a398ae5 100644 (file)
@@ -7,6 +7,23 @@
 #define IP6_RT_PRIO_KERN       512
 #define IP6_RT_FLOW_MASK       0x00ff
 
+struct route_info {
+       __u8                    type;
+       __u8                    length;
+       __u8                    prefix_len;
+#if defined(__BIG_ENDIAN_BITFIELD)
+       __u8                    reserved_h:3,
+                               route_pref:2,
+                               reserved_l:3;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8                    reserved_l:3,
+                               route_pref:2,
+                               reserved_h:3;
+#endif
+       __u32                   lifetime;
+       __u8                    prefix[0];      /* 0,8 or 16 */
+};
+
 #ifdef __KERNEL__
 
 #include <net/flow.h>
@@ -87,11 +104,14 @@ extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 extern struct rt6_info *       rt6_get_dflt_router(struct in6_addr *addr,
                                                    struct net_device *dev);
 extern struct rt6_info *       rt6_add_dflt_router(struct in6_addr *gwaddr,
-                                                   struct net_device *dev);
+                                                   struct net_device *dev,
+                                                   unsigned int pref);
 
 extern void                    rt6_purge_dflt_routers(void);
 
-extern void                    rt6_reset_dflt_pointer(struct rt6_info *rt);
+extern int                     rt6_route_rcv(struct net_device *dev,
+                                             u8 *opt, int len,
+                                             struct in6_addr *gwaddr);
 
 extern void                    rt6_redirect(struct in6_addr *dest,
                                             struct in6_addr *saddr,
index 3b1d963..6d6f063 100644 (file)
@@ -282,6 +282,18 @@ static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr
        return memcmp((const void *) a1, (const void *) a2, sizeof(struct in6_addr));
 }
 
+static inline int
+ipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m,
+                    const struct in6_addr *a2)
+{
+       unsigned int i;
+
+       for (i = 0; i < 4; i++)
+               if ((a1->s6_addr32[i] ^ a2->s6_addr32[i]) & m->s6_addr32[i])
+                       return 1;
+       return 0;
+}
+
 static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)
 {
        memcpy((void *) a1, (const void *) a2, sizeof(struct in6_addr));
@@ -508,6 +520,16 @@ extern int                 ipv6_getsockopt(struct sock *sk, int level,
                                                int optname,
                                                char __user *optval, 
                                                int __user *optlen);
+extern int                     compat_ipv6_setsockopt(struct sock *sk,
+                                               int level,
+                                               int optname,
+                                               char __user *optval,
+                                               int optlen);
+extern int                     compat_ipv6_getsockopt(struct sock *sk,
+                                               int level,
+                                               int optname,
+                                               char __user *optval,
+                                               int __user *optlen);
 
 extern void                    ipv6_packet_init(void);
 
index 1adb2ef..f502458 100644 (file)
@@ -71,7 +71,7 @@ extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
                   struct packet_type *pt, struct net_device *orig_dev);
 
 extern int llc_mac_hdr_init(struct sk_buff *skb,
-                           unsigned char *sa, unsigned char *da);
+                           const unsigned char *sa, const unsigned char *da);
 
 extern void llc_add_pack(int type, void (*handler)(struct llc_sap *sap,
                                                   struct sk_buff *skb));
index bbac87e..91fa271 100644 (file)
@@ -22,6 +22,8 @@ enum {
        ND_OPT_PREFIX_INFO = 3,         /* RFC2461 */
        ND_OPT_REDIRECT_HDR = 4,        /* RFC2461 */
        ND_OPT_MTU = 5,                 /* RFC2461 */
+       __ND_OPT_ARRAY_MAX,
+       ND_OPT_ROUTE_INFO = 24,         /* RFC4191 */
        __ND_OPT_MAX
 };
 
index 6fa9ae1..b0666d6 100644 (file)
@@ -68,6 +68,7 @@ struct neigh_parms
        struct net_device *dev;
        struct neigh_parms *next;
        int     (*neigh_setup)(struct neighbour *);
+       void    (*neigh_destructor)(struct neighbour *);
        struct neigh_table *tbl;
 
        void    *sysctl_table;
@@ -145,7 +146,6 @@ struct neighbour
 struct neigh_ops
 {
        int                     family;
-       void                    (*destructor)(struct neighbour *);
        void                    (*solicit)(struct neighbour *, struct sk_buff*);
        void                    (*error_report)(struct neighbour *, struct sk_buff*);
        int                     (*output)(struct sk_buff*);
index 6d075ca..2743c15 100644 (file)
@@ -67,6 +67,18 @@ do {                                                                 \
 
 struct nf_conntrack_helper;
 
+/* nf_conn feature for connections that have a helper */
+struct nf_conn_help {
+       /* Helper. if any */
+       struct nf_conntrack_helper *helper;
+
+       union nf_conntrack_help help;
+
+       /* Current number of expected connections */
+       unsigned int expecting;
+};
+
+
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 struct nf_conn
 {
@@ -81,6 +93,9 @@ struct nf_conn
        /* Have we seen traffic both ways yet? (bitset) */
        unsigned long status;
 
+       /* If we were expected by an expectation, this will be it */
+       struct nf_conn *master;
+
        /* Timer function; drops refcnt when it goes off. */
        struct timer_list timeout;
 
@@ -88,38 +103,22 @@ struct nf_conn
        /* Accounting Information (same cache line as other written members) */
        struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
 #endif
-       /* If we were expected by an expectation, this will be it */
-       struct nf_conn *master;
-       
-       /* Current number of expected connections */
-       unsigned int expecting;
 
        /* Unique ID that identifies this conntrack*/
        unsigned int id;
 
-       /* Helper. if any */
-       struct nf_conntrack_helper *helper;
-
        /* features - nat, helper, ... used by allocating system */
        u_int32_t features;
 
-       /* Storage reserved for other modules: */
-
-       union nf_conntrack_proto proto;
-
 #if defined(CONFIG_NF_CONNTRACK_MARK)
        u_int32_t mark;
 #endif
 
-       /* These members are dynamically allocated. */
-
-       union nf_conntrack_help *help;
+       /* Storage reserved for other modules: */
+       union nf_conntrack_proto proto;
 
-       /* Layer 3 dependent members. (ex: NAT) */
-       union {
-               struct nf_conntrack_ipv4 *ipv4;
-       } l3proto;
-       void *data[0];
+       /* features dynamically at the end: helper, nat (both optional) */
+       char data[0];
 };
 
 struct nf_conntrack_expect
@@ -373,10 +372,23 @@ nf_conntrack_expect_event(enum ip_conntrack_expect_events event,
 #define NF_CT_F_NUM    4
 
 extern int
-nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size,
-                           int (*init_conntrack)(struct nf_conn *, u_int32_t));
+nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size);
 extern void
 nf_conntrack_unregister_cache(u_int32_t features);
 
+/* valid combinations:
+ * basic: nf_conn, nf_conn .. nf_conn_help
+ * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat, nf_conn help
+ */
+static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
+{
+       unsigned int offset = sizeof(struct nf_conn);
+
+       if (!(ct->features & NF_CT_F_HELP))
+               return NULL;
+
+       return (struct nf_conn_help *) ((void *)ct + offset);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _NF_CONNTRACK_H */
index c3fa3d5..540619c 100644 (file)
@@ -37,10 +37,12 @@ static __inline__ void scm_destroy(struct scm_cookie *scm)
 static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
                               struct scm_cookie *scm)
 {
-       memset(scm, 0, sizeof(*scm));
-       scm->creds.uid = current->uid;
-       scm->creds.gid = current->gid;
-       scm->creds.pid = current->tgid;
+       struct task_struct *p = current;
+       scm->creds.uid = p->uid;
+       scm->creds.gid = p->gid;
+       scm->creds.pid = p->tgid;
+       scm->fp = NULL;
+       scm->seq = 0;
        if (msg->msg_controllen <= 0)
                return 0;
        return __scm_send(sock, msg, scm);
index 072f407..eba99f3 100644 (file)
@@ -514,6 +514,16 @@ struct sctp_af {
                                         int optname,
                                         char __user *optval,
                                         int __user *optlen);
+       int             (*compat_setsockopt)    (struct sock *sk,
+                                        int level,
+                                        int optname,
+                                        char __user *optval,
+                                        int optlen);
+       int             (*compat_getsockopt)    (struct sock *sk,
+                                        int level,
+                                        int optname,
+                                        char __user *optval,
+                                        int __user *optlen);
        struct dst_entry *(*get_dst)    (struct sctp_association *asoc,
                                         union sctp_addr *daddr,
                                         union sctp_addr *saddr);
index f63d0d5..ec226f3 100644 (file)
@@ -520,6 +520,14 @@ struct proto {
        int                     (*getsockopt)(struct sock *sk, int level, 
                                        int optname, char __user *optval, 
                                        int __user *option);     
+       int                     (*compat_setsockopt)(struct sock *sk,
+                                       int level,
+                                       int optname, char __user *optval,
+                                       int optlen);
+       int                     (*compat_getsockopt)(struct sock *sk,
+                                       int level,
+                                       int optname, char __user *optval,
+                                       int __user *option);
        int                     (*sendmsg)(struct kiocb *iocb, struct sock *sk,
                                           struct msghdr *msg, size_t len);
        int                     (*recvmsg)(struct kiocb *iocb, struct sock *sk,
@@ -816,6 +824,10 @@ extern int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock,
                               struct msghdr *msg, size_t size, int flags);
 extern int sock_common_setsockopt(struct socket *sock, int level, int optname,
                                  char __user *optval, int optlen);
+extern int compat_sock_common_getsockopt(struct socket *sock, int level,
+               int optname, char __user *optval, int __user *optlen);
+extern int compat_sock_common_setsockopt(struct socket *sock, int level,
+               int optname, char __user *optval, int optlen);
 
 extern void sk_common_release(struct sock *sk);
 
index 77f21c6..9418f4d 100644 (file)
@@ -60,6 +60,9 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
 /* Minimal RCV_MSS. */
 #define TCP_MIN_RCVMSS         536U
 
+/* The least MTU to use for probing */
+#define TCP_BASE_MSS           512
+
 /* After receiving this amount of duplicate ACKs fast retransmit starts. */
 #define TCP_FASTRETRANS_THRESH 3
 
@@ -219,6 +222,9 @@ extern int sysctl_tcp_nometrics_save;
 extern int sysctl_tcp_moderate_rcvbuf;
 extern int sysctl_tcp_tso_win_divisor;
 extern int sysctl_tcp_abc;
+extern int sysctl_tcp_mtu_probing;
+extern int sysctl_tcp_base_mss;
+extern int sysctl_tcp_workaround_signed_windows;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -347,6 +353,12 @@ extern int                 tcp_getsockopt(struct sock *sk, int level,
 extern int                     tcp_setsockopt(struct sock *sk, int level, 
                                               int optname, char __user *optval, 
                                               int optlen);
+extern int                     compat_tcp_getsockopt(struct sock *sk,
+                                       int level, int optname,
+                                       char __user *optval, int __user *optlen);
+extern int                     compat_tcp_setsockopt(struct sock *sk,
+                                       int level, int optname,
+                                       char __user *optval, int optlen);
 extern void                    tcp_set_keepalive(struct sock *sk, int val);
 extern int                     tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
                                            struct msghdr *msg,
@@ -447,6 +459,10 @@ extern int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 
 extern void tcp_initialize_rcv_mss(struct sock *sk);
 
+extern int tcp_mtu_to_mss(struct sock *sk, int pmtu);
+extern int tcp_mss_to_mtu(struct sock *sk, int mss);
+extern void tcp_mtup_init(struct sock *sk);
+
 static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)
 {
        tp->pred_flags = htonl((tp->tcp_header_len << 26) |
index 8d362c4..61b7504 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/crypto.h>
 #include <linux/pfkeyv2.h>
 #include <linux/in6.h>
+#include <linux/mutex.h>
 
 #include <net/sock.h>
 #include <net/dst.h>
 
 #define XFRM_ALIGN8(len)       (((len) + 7) & ~7)
 
-extern struct semaphore xfrm_cfg_sem;
+extern struct sock *xfrm_nl;
+extern u32 sysctl_xfrm_aevent_etime;
+extern u32 sysctl_xfrm_aevent_rseqth;
+
+extern struct mutex xfrm_cfg_mutex;
 
 /* Organization of SPD aka "XFRM rules"
    ------------------------------------
@@ -135,6 +140,16 @@ struct xfrm_state
        /* State for replay detection */
        struct xfrm_replay_state replay;
 
+       /* Replay detection state at the time we sent the last notification */
+       struct xfrm_replay_state preplay;
+
+       /* Replay detection notification settings */
+       u32                     replay_maxage;
+       u32                     replay_maxdiff;
+
+       /* Replay detection notification timer */
+       struct timer_list       rtimer;
+
        /* Statistics */
        struct xfrm_stats       stats;
 
@@ -169,6 +184,7 @@ struct km_event
                u32 hard;
                u32 proto;
                u32 byid;
+               u32 aevent;
        } data;
 
        u32     seq;
@@ -199,10 +215,13 @@ extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
 extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
 extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c);
 extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
-
 #define XFRM_ACQ_EXPIRES       30
 
 struct xfrm_tmpl;
+extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
+extern void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
+extern int __xfrm_state_delete(struct xfrm_state *x);
+
 struct xfrm_state_afinfo {
        unsigned short          family;
        rwlock_t                lock;
@@ -305,7 +324,21 @@ struct xfrm_policy
        struct xfrm_tmpl        xfrm_vec[XFRM_MAX_DEPTH];
 };
 
-#define XFRM_KM_TIMEOUT                30
+#define XFRM_KM_TIMEOUT                30
+/* which seqno */
+#define XFRM_REPLAY_SEQ                1
+#define XFRM_REPLAY_OSEQ       2
+#define XFRM_REPLAY_SEQ_MASK   3
+/* what happened */
+#define XFRM_REPLAY_UPDATE     XFRM_AE_CR
+#define XFRM_REPLAY_TIMEOUT    XFRM_AE_CE
+
+/* default aevent timeout in units of 100ms */
+#define XFRM_AE_ETIME                  10
+/* Async Event timer multiplier */
+#define XFRM_AE_ETH_M                  10
+/* default seq threshold size */
+#define XFRM_AE_SEQT_SIZE              2
 
 struct xfrm_mgr
 {
@@ -865,6 +898,7 @@ extern int xfrm_state_delete(struct xfrm_state *x);
 extern void xfrm_state_flush(u8 proto);
 extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
+extern void xfrm_replay_notify(struct xfrm_state *x, int event);
 extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
 extern int xfrm_init_state(struct xfrm_state *x);
@@ -924,7 +958,7 @@ extern void xfrm_init_pmtu(struct dst_entry *dst);
 
 extern wait_queue_head_t km_waitq;
 extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
-extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard);
+extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid);
 
 extern void xfrm_input_init(void);
 extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq);
@@ -965,4 +999,24 @@ static inline int xfrm_policy_id2dir(u32 index)
        return index & 7;
 }
 
+static inline int xfrm_aevent_is_on(void)
+{
+       struct sock *nlsk;
+       int ret = 0;
+
+       rcu_read_lock();
+       nlsk = rcu_dereference(xfrm_nl);
+       if (nlsk)
+               ret = netlink_has_listeners(nlsk, XFRMNLGRP_AEVENTS);
+       rcu_read_unlock();
+       return ret;
+}
+
+static inline void xfrm_aevent_doreplay(struct xfrm_state *x)
+{
+       if (xfrm_aevent_is_on())
+               xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
+}
+
+
 #endif /* _NET_XFRM_H */
index 86b7e93..4ace54c 100644 (file)
@@ -43,6 +43,7 @@ struct ib_fmr_pool;
 /**
  * struct ib_fmr_pool_param - Parameters for creating FMR pool
  * @max_pages_per_fmr:Maximum number of pages per map request.
+ * @page_shift: Log2 of sizeof "pages" mapped by this fmr
  * @access:Access flags for FMRs in pool.
  * @pool_size:Number of FMRs to allocate for pool.
  * @dirty_watermark:Flush is triggered when @dirty_watermark dirty
@@ -55,6 +56,7 @@ struct ib_fmr_pool;
  */
 struct ib_fmr_pool_param {
        int                     max_pages_per_fmr;
+       int                     page_shift;
        enum ib_access_flags    access;
        int                     pool_size;
        int                     dirty_watermark;
index 2c13350..51ab8ed 100644 (file)
@@ -33,7 +33,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: ib_mad.h 2775 2005-07-02 13:42:12Z halr $
+ * $Id: ib_mad.h 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 
 #if !defined( IB_MAD_H )
@@ -208,15 +208,23 @@ struct ib_class_port_info
 /**
  * ib_mad_send_buf - MAD data buffer and work request for sends.
  * @next: A pointer used to chain together MADs for posting.
- * @mad: References an allocated MAD data buffer.
+ * @mad: References an allocated MAD data buffer for MADs that do not have
+ *   RMPP active.  For MADs using RMPP, references the common and management
+ *   class specific headers.
  * @mad_agent: MAD agent that allocated the buffer.
  * @ah: The address handle to use when sending the MAD.
  * @context: User-controlled context fields.
+ * @hdr_len: Indicates the size of the data header of the MAD.  This length
+ *   includes the common MAD, RMPP, and class specific headers.
+ * @data_len: Indicates the total size of user-transferred data.
+ * @seg_count: The number of RMPP segments allocated for this send.
+ * @seg_size: Size of each RMPP segment.
  * @timeout_ms: Time to wait for a response.
  * @retries: Number of times to retry a request for a response.
  *
  * Users are responsible for initializing the MAD buffer itself, with the
- * exception of specifying the payload length field in any RMPP MAD.
+ * exception of any RMPP header.  Additional segment buffer space allocated
+ * beyond data_len is padding.
  */
 struct ib_mad_send_buf {
        struct ib_mad_send_buf  *next;
@@ -224,6 +232,10 @@ struct ib_mad_send_buf {
        struct ib_mad_agent     *mad_agent;
        struct ib_ah            *ah;
        void                    *context[2];
+       int                     hdr_len;
+       int                     data_len;
+       int                     seg_count;
+       int                     seg_size;
        int                     timeout_ms;
        int                     retries;
 };
@@ -299,7 +311,7 @@ typedef void (*ib_mad_snoop_handler)(struct ib_mad_agent *mad_agent,
  * @mad_recv_wc: Received work completion information on the received MAD.
  *
  * MADs received in response to a send request operation will be handed to
- * the user after the send operation completes.  All data buffers given
+ * the user before the send operation completes.  All data buffers given
  * to registered agents through this routine are owned by the receiving
  * client, except for snooping agents.  Clients snooping MADs should not
  * modify the data referenced by @mad_recv_wc.
@@ -485,17 +497,6 @@ int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent);
 int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
                     struct ib_mad_send_buf **bad_send_buf);
 
-/**
- * ib_coalesce_recv_mad - Coalesces received MAD data into a single buffer.
- * @mad_recv_wc: Work completion information for a received MAD.
- * @buf: User-provided data buffer to receive the coalesced buffers.  The
- *   referenced buffer should be at least the size of the mad_len specified
- *   by @mad_recv_wc.
- *
- * This call copies a chain of received MAD segments into a single data buffer,
- * removing duplicated headers.
- */
-void ib_coalesce_recv_mad(struct ib_mad_recv_wc *mad_recv_wc, void *buf);
 
 /**
  * ib_free_recv_mad - Returns data buffers used to receive a MAD.
@@ -590,9 +591,10 @@ int ib_process_mad_wc(struct ib_mad_agent *mad_agent,
  * with an initialized work request structure.  Users may modify the returned
  * MAD data buffer before posting the send.
  *
- * The returned data buffer will be cleared.  Users are responsible for
- * initializing the common MAD and any class specific headers.  If @rmpp_active
- * is set, the RMPP header will be initialized for sending.
+ * The returned MAD header, class specific headers, and any padding will be
+ * cleared.  Users are responsible for initializing the common MAD header,
+ * any class specific header, and MAD data area.
+ * If @rmpp_active is set, the RMPP header will be initialized for sending.
  */
 struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
                                            u32 remote_qpn, u16 pkey_index,
@@ -601,6 +603,16 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
                                            gfp_t gfp_mask);
 
 /**
+ * ib_get_rmpp_segment - returns the data buffer for a given RMPP segment.
+ * @send_buf: Previously allocated send data buffer.
+ * @seg_num: number of segment to return
+ *
+ * This routine returns a pointer to the data buffer of an RMPP MAD.
+ * Users must provide synchronization to @send_buf around this call.
+ */
+void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num);
+
+/**
  * ib_free_send_mad - Returns data buffers used to send a MAD.
  * @send_buf: Previously allocated send data buffer.
  */
index 5ff1490..338ed43 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
+ * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -43,7 +44,7 @@
  * Increment this value if any changes that break userspace ABI
  * compatibility are made.
  */
-#define IB_USER_VERBS_ABI_VERSION      4
+#define IB_USER_VERBS_ABI_VERSION      6
 
 enum {
        IB_USER_VERBS_CMD_GET_CONTEXT,
@@ -265,6 +266,17 @@ struct ib_uverbs_create_cq_resp {
        __u32 cqe;
 };
 
+struct ib_uverbs_resize_cq {
+       __u64 response;
+       __u32 cq_handle;
+       __u32 cqe;
+       __u64 driver_data[0];
+};
+
+struct ib_uverbs_resize_cq_resp {
+       __u32 cqe;
+};
+
 struct ib_uverbs_poll_cq {
        __u64 response;
        __u32 cq_handle;
@@ -338,6 +350,7 @@ struct ib_uverbs_create_qp_resp {
        __u32 max_send_sge;
        __u32 max_recv_sge;
        __u32 max_inline_data;
+       __u32 reserved;
 };
 
 /*
@@ -359,6 +372,47 @@ struct ib_uverbs_qp_dest {
        __u8  port_num;
 };
 
+struct ib_uverbs_query_qp {
+       __u64 response;
+       __u32 qp_handle;
+       __u32 attr_mask;
+       __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_qp_resp {
+       struct ib_uverbs_qp_dest dest;
+       struct ib_uverbs_qp_dest alt_dest;
+       __u32 max_send_wr;
+       __u32 max_recv_wr;
+       __u32 max_send_sge;
+       __u32 max_recv_sge;
+       __u32 max_inline_data;
+       __u32 qkey;
+       __u32 rq_psn;
+       __u32 sq_psn;
+       __u32 dest_qp_num;
+       __u32 qp_access_flags;
+       __u16 pkey_index;
+       __u16 alt_pkey_index;
+       __u8  qp_state;
+       __u8  cur_qp_state;
+       __u8  path_mtu;
+       __u8  path_mig_state;
+       __u8  en_sqd_async_notify;
+       __u8  max_rd_atomic;
+       __u8  max_dest_rd_atomic;
+       __u8  min_rnr_timer;
+       __u8  port_num;
+       __u8  timeout;
+       __u8  retry_cnt;
+       __u8  rnr_retry;
+       __u8  alt_port_num;
+       __u8  alt_timeout;
+       __u8  sq_sig_all;
+       __u8  reserved[5];
+       __u64 driver_data[0];
+};
+
 struct ib_uverbs_modify_qp {
        struct ib_uverbs_qp_dest dest;
        struct ib_uverbs_qp_dest alt_dest;
@@ -415,7 +469,7 @@ struct ib_uverbs_sge {
 };
 
 struct ib_uverbs_send_wr {
-       __u64 wr_id; 
+       __u64 wr_id;
        __u32 num_sge;
        __u32 opcode;
        __u32 send_flags;
@@ -489,7 +543,7 @@ struct ib_uverbs_post_srq_recv_resp {
 
 struct ib_uverbs_global_route {
        __u8  dgid[16];
-       __u32 flow_label;    
+       __u32 flow_label;
        __u8  sgid_index;
        __u8  hop_limit;
        __u8  traffic_class;
@@ -551,6 +605,9 @@ struct ib_uverbs_create_srq {
 
 struct ib_uverbs_create_srq_resp {
        __u32 srq_handle;
+       __u32 max_wr;
+       __u32 max_sge;
+       __u32 reserved;
 };
 
 struct ib_uverbs_modify_srq {
@@ -561,6 +618,20 @@ struct ib_uverbs_modify_srq {
        __u64 driver_data[0];
 };
 
+struct ib_uverbs_query_srq {
+       __u64 response;
+       __u32 srq_handle;
+       __u32 reserved;
+       __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_srq_resp {
+       __u32 max_wr;
+       __u32 max_sge;
+       __u32 srq_limit;
+       __u32 reserved;
+};
+
 struct ib_uverbs_destroy_srq {
        __u64 response;
        __u32 srq_handle;
index 22fc886..c1ad627 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -222,11 +222,13 @@ struct ib_port_attr {
 };
 
 enum ib_device_modify_flags {
-       IB_DEVICE_MODIFY_SYS_IMAGE_GUID = 1
+       IB_DEVICE_MODIFY_SYS_IMAGE_GUID = 1 << 0,
+       IB_DEVICE_MODIFY_NODE_DESC      = 1 << 1
 };
 
 struct ib_device_modify {
        u64     sys_image_guid;
+       char    node_desc[64];
 };
 
 enum ib_port_modify_flags {
@@ -649,7 +651,7 @@ struct ib_mw_bind {
 struct ib_fmr_attr {
        int     max_pages;
        int     max_maps;
-       u8      page_size;
+       u8      page_shift;
 };
 
 struct ib_ucontext {
@@ -880,7 +882,8 @@ struct ib_device {
                                                struct ib_ucontext *context,
                                                struct ib_udata *udata);
        int                        (*destroy_cq)(struct ib_cq *cq);
-       int                        (*resize_cq)(struct ib_cq *cq, int cqe);
+       int                        (*resize_cq)(struct ib_cq *cq, int cqe,
+                                               struct ib_udata *udata);
        int                        (*poll_cq)(struct ib_cq *cq, int num_entries,
                                              struct ib_wc *wc);
        int                        (*peek_cq)(struct ib_cq *cq, int wc_cnt);
@@ -950,6 +953,7 @@ struct ib_device {
        u64                          uverbs_cmd_mask;
        int                          uverbs_abi_ver;
 
+       char                         node_desc[64];
        __be64                       node_guid;
        u8                           node_type;
        u8                           phys_port_cnt;
@@ -986,6 +990,24 @@ static inline int ib_copy_to_udata(struct ib_udata *udata, void *src, size_t len
        return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0;
 }
 
+/**
+ * ib_modify_qp_is_ok - Check that the supplied attribute mask
+ * contains all required attributes and no attributes not allowed for
+ * the given QP state transition.
+ * @cur_state: Current QP state
+ * @next_state: Next QP state
+ * @type: QP type
+ * @mask: Mask of supplied QP attributes
+ *
+ * This function is a helper function that a low-level driver's
+ * modify_qp method can use to validate the consumer's input.  It
+ * checks that cur_state and next_state are valid QP states, that a
+ * transition from cur_state to next_state is allowed by the IB spec,
+ * and that the attribute mask supplied is allowed for the transition.
+ */
+int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
+                      enum ib_qp_type type, enum ib_qp_attr_mask mask);
+
 int ib_register_event_handler  (struct ib_event_handler *event_handler);
 int ib_unregister_event_handler(struct ib_event_handler *event_handler);
 void ib_dispatch_event(struct ib_event *event);
@@ -1078,7 +1100,9 @@ int ib_destroy_ah(struct ib_ah *ah);
  * ib_create_srq - Creates a SRQ associated with the specified protection
  *   domain.
  * @pd: The protection domain associated with the SRQ.
- * @srq_init_attr: A list of initial attributes required to create the SRQ.
+ * @srq_init_attr: A list of initial attributes required to create the
+ *   SRQ.  If SRQ creation succeeds, then the attributes are updated to
+ *   the actual capabilities of the created SRQ.
  *
  * srq_attr->max_wr and srq_attr->max_sge are read the determine the
  * requested size of the SRQ, and set to the actual values allocated
@@ -1137,7 +1161,9 @@ static inline int ib_post_srq_recv(struct ib_srq *srq,
  * ib_create_qp - Creates a QP associated with the specified protection
  *   domain.
  * @pd: The protection domain associated with the QP.
- * @qp_init_attr: A list of initial attributes required to create the QP.
+ * @qp_init_attr: A list of initial attributes required to create the
+ *   QP.  If QP creation succeeds, then the attributes are updated to
+ *   the actual capabilities of the created QP.
  */
 struct ib_qp *ib_create_qp(struct ib_pd *pd,
                           struct ib_qp_init_attr *qp_init_attr);
index fabd879..d160880 100644 (file)
@@ -35,6 +35,9 @@ static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
 }
 
 
+extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
+                              struct list_head *done_q);
+extern void scsi_eh_flush_done_q(struct list_head *done_q);
 extern void scsi_report_bus_reset(struct Scsi_Host *, int);
 extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
 extern int scsi_block_when_processing_errors(struct scsi_device *);
index d5eeae0..f2690ed 100644 (file)
@@ -15,9 +15,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 
-u64 uevent_seqnum;
-char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
-
 #define KERNEL_ATTR_RO(_name) \
 static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
 
index 5aad477..77764f2 100644 (file)
@@ -126,8 +126,11 @@ extern const struct kernel_symbol __start___ksymtab[];
 extern const struct kernel_symbol __stop___ksymtab[];
 extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
+extern const unsigned long __start___kcrctab_gpl_future[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -135,6 +138,18 @@ extern const unsigned long __start___kcrctab_gpl[];
 #define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
 #endif
 
+/* lookup symbol in given range of kernel_symbols */
+static const struct kernel_symbol *lookup_symbol(const char *name,
+       const struct kernel_symbol *start,
+       const struct kernel_symbol *stop)
+{
+       const struct kernel_symbol *ks = start;
+       for (; ks < stop; ks++)
+               if (strcmp(ks->name, name) == 0)
+                       return ks;
+       return NULL;
+}
+
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
                                   struct module **owner,
@@ -142,40 +157,75 @@ static unsigned long __find_symbol(const char *name,
                                   int gplok)
 {
        struct module *mod;
-       unsigned int i;
+       const struct kernel_symbol *ks;
 
        /* Core kernel first. */ 
        *owner = NULL;
-       for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) {
-               if (strcmp(__start___ksymtab[i].name, name) == 0) {
-                       *crc = symversion(__start___kcrctab, i);
-                       return __start___ksymtab[i].value;
-               }
+       ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
+       if (ks) {
+               *crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
+               return ks->value;
        }
        if (gplok) {
-               for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++)
-                       if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) {
-                               *crc = symversion(__start___kcrctab_gpl, i);
-                               return __start___ksymtab_gpl[i].value;
-                       }
+               ks = lookup_symbol(name, __start___ksymtab_gpl,
+                                        __stop___ksymtab_gpl);
+               if (ks) {
+                       *crc = symversion(__start___kcrctab_gpl,
+                                         (ks - __start___ksymtab_gpl));
+                       return ks->value;
+               }
+       }
+       ks = lookup_symbol(name, __start___ksymtab_gpl_future,
+                                __stop___ksymtab_gpl_future);
+       if (ks) {
+               if (!gplok) {
+                       printk(KERN_WARNING "Symbol %s is being used "
+                              "by a non-GPL module, which will not "
+                              "be allowed in the future\n", name);
+                       printk(KERN_WARNING "Please see the file "
+                              "Documentation/feature-removal-schedule.txt "
+                              "in the kernel source tree for more "
+                              "details.\n");
+               }
+               *crc = symversion(__start___kcrctab_gpl_future,
+                                 (ks - __start___ksymtab_gpl_future));
+               return ks->value;
        }
 
        /* Now try modules. */ 
        list_for_each_entry(mod, &modules, list) {
                *owner = mod;
-               for (i = 0; i < mod->num_syms; i++)
-                       if (strcmp(mod->syms[i].name, name) == 0) {
-                               *crc = symversion(mod->crcs, i);
-                               return mod->syms[i].value;
-                       }
+               ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
+               if (ks) {
+                       *crc = symversion(mod->crcs, (ks - mod->syms));
+                       return ks->value;
+               }
 
                if (gplok) {
-                       for (i = 0; i < mod->num_gpl_syms; i++) {
-                               if (strcmp(mod->gpl_syms[i].name, name) == 0) {
-                                       *crc = symversion(mod->gpl_crcs, i);
-                                       return mod->gpl_syms[i].value;
-                               }
+                       ks = lookup_symbol(name, mod->gpl_syms,
+                                          mod->gpl_syms + mod->num_gpl_syms);
+                       if (ks) {
+                               *crc = symversion(mod->gpl_crcs,
+                                                 (ks - mod->gpl_syms));
+                               return ks->value;
+                       }
+               }
+               ks = lookup_symbol(name, mod->gpl_future_syms,
+                                  (mod->gpl_future_syms +
+                                   mod->num_gpl_future_syms));
+               if (ks) {
+                       if (!gplok) {
+                               printk(KERN_WARNING "Symbol %s is being used "
+                                      "by a non-GPL module, which will not "
+                                      "be allowed in the future\n", name);
+                               printk(KERN_WARNING "Please see the file "
+                                      "Documentation/feature-removal-schedule.txt "
+                                      "in the kernel source tree for more "
+                                      "details.\n");
                        }
+                       *crc = symversion(mod->gpl_future_crcs,
+                                         (ks - mod->gpl_future_syms));
+                       return ks->value;
                }
        }
        DEBUGP("Failed to find symbol %s\n", name);
@@ -379,7 +429,6 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
 }
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_MODULE_UNLOAD
 #define MODINFO_ATTR(field)    \
 static void setup_modinfo_##field(struct module *mod, const char *s)  \
 {                                                                     \
@@ -411,12 +460,7 @@ static struct module_attribute modinfo_##field = {                    \
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
-static struct module_attribute *modinfo_attrs[] = {
-       &modinfo_version,
-       &modinfo_srcversion,
-       NULL,
-};
-
+#ifdef CONFIG_MODULE_UNLOAD
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
 {
@@ -731,6 +775,15 @@ static inline void module_unload_init(struct module *mod)
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
+static struct module_attribute *modinfo_attrs[] = {
+       &modinfo_version,
+       &modinfo_srcversion,
+#ifdef CONFIG_MODULE_UNLOAD
+       &refcnt,
+#endif
+       NULL,
+};
+
 #ifdef CONFIG_OBSOLETE_MODPARM
 /* Bounds checking done below */
 static int obsparm_copy_string(const char *val, struct kernel_param *kp)
@@ -1056,37 +1109,28 @@ static inline void remove_sect_attrs(struct module *mod)
 }
 #endif /* CONFIG_KALLSYMS */
 
-
-#ifdef CONFIG_MODULE_UNLOAD
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-       return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr);
-}
-static void module_remove_refcnt_attr(struct module *mod)
-{
-       return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr);
-}
-#else
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-       return 0;
-}
-static void module_remove_refcnt_attr(struct module *mod)
-{
-}
-#endif
-
-#ifdef CONFIG_MODULE_UNLOAD
 static int module_add_modinfo_attrs(struct module *mod)
 {
        struct module_attribute *attr;
+       struct module_attribute *temp_attr;
        int error = 0;
        int i;
 
+       mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
+                                       (ARRAY_SIZE(modinfo_attrs) + 1)),
+                                       GFP_KERNEL);
+       if (!mod->modinfo_attrs)
+               return -ENOMEM;
+
+       temp_attr = mod->modinfo_attrs;
        for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
                if (!attr->test ||
-                   (attr->test && attr->test(mod)))
-                       error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr);
+                   (attr->test && attr->test(mod))) {
+                       memcpy(temp_attr, attr, sizeof(*temp_attr));
+                       temp_attr->attr.owner = mod;
+                       error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
+                       ++temp_attr;
+               }
        }
        return error;
 }
@@ -1096,12 +1140,16 @@ static void module_remove_modinfo_attrs(struct module *mod)
        struct module_attribute *attr;
        int i;
 
-       for (i = 0; (attr = modinfo_attrs[i]); i++) {
+       for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
+               /* pick a field to test for end of list */
+               if (!attr->attr.name)
+                       break;
                sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
-               attr->free(mod);
+               if (attr->free)
+                       attr->free(mod);
        }
+       kfree(mod->modinfo_attrs);
 }
-#endif
 
 static int mod_sysfs_setup(struct module *mod,
                           struct kernel_param *kparam,
@@ -1119,19 +1167,13 @@ static int mod_sysfs_setup(struct module *mod,
        if (err)
                goto out;
 
-       err = module_add_refcnt_attr(mod);
-       if (err)
-               goto out_unreg;
-
        err = module_param_sysfs_setup(mod, kparam, num_params);
        if (err)
                goto out_unreg;
 
-#ifdef CONFIG_MODULE_UNLOAD
        err = module_add_modinfo_attrs(mod);
        if (err)
                goto out_unreg;
-#endif
 
        return 0;
 
@@ -1143,10 +1185,7 @@ out:
 
 static void mod_kobject_remove(struct module *mod)
 {
-#ifdef CONFIG_MODULE_UNLOAD
        module_remove_modinfo_attrs(mod);
-#endif
-       module_remove_refcnt_attr(mod);
        module_param_sysfs_remove(mod);
 
        kobject_unregister(&mod->mkobj.kobj);
@@ -1424,7 +1463,6 @@ static char *get_modinfo(Elf_Shdr *sechdrs,
        return NULL;
 }
 
-#ifdef CONFIG_MODULE_UNLOAD
 static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
                          unsigned int infoindex)
 {
@@ -1439,23 +1477,17 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
                                                attr->attr.name));
        }
 }
-#endif
 
 #ifdef CONFIG_KALLSYMS
 int is_exported(const char *name, const struct module *mod)
 {
-       unsigned int i;
-
-       if (!mod) {
-               for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++)
-                       if (strcmp(__start___ksymtab[i].name, name) == 0)
-                               return 1;
-               return 0;
-       }
-       for (i = 0; i < mod->num_syms; i++)
-               if (strcmp(mod->syms[i].name, name) == 0)
+       if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
+               return 1;
+       else
+               if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
                        return 1;
-       return 0;
+               else
+                       return 0;
 }
 
 /* As per nm */
@@ -1537,7 +1569,8 @@ static struct module *load_module(void __user *umod,
        char *secstrings, *args, *modmagic, *strtab = NULL;
        unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
                exportindex, modindex, obsparmindex, infoindex, gplindex,
-               crcindex, gplcrcindex, versindex, pcpuindex;
+               crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
+               gplfuturecrcindex;
        long arglen;
        struct module *mod;
        long err = 0;
@@ -1618,8 +1651,10 @@ static struct module *load_module(void __user *umod,
        /* Optional sections */
        exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
        gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
+       gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
        crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
        gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
+       gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
        setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
        exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
        obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
@@ -1755,10 +1790,8 @@ static struct module *load_module(void __user *umod,
        if (strcmp(mod->name, "driverloader") == 0)
                add_taint(TAINT_PROPRIETARY_MODULE);
 
-#ifdef CONFIG_MODULE_UNLOAD
        /* Set up MODINFO_ATTR fields */
        setup_modinfo(mod, sechdrs, infoindex);
-#endif
 
        /* Fix up syms, so that st_value is a pointer to location. */
        err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
@@ -1775,10 +1808,16 @@ static struct module *load_module(void __user *umod,
        mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
        if (gplcrcindex)
                mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
+       mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
+                                       sizeof(*mod->gpl_future_syms);
+       mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
+       if (gplfuturecrcindex)
+               mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
 
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !crcindex) || 
-           (mod->num_gpl_syms && !gplcrcindex)) {
+           (mod->num_gpl_syms && !gplcrcindex) ||
+           (mod->num_gpl_future_syms && !gplfuturecrcindex)) {
                printk(KERN_WARNING "%s: No versions for exported symbols."
                       " Tainting kernel.\n", mod->name);
                add_taint(TAINT_FORCED_MODULE);
index c76ad25..a291505 100644 (file)
@@ -638,13 +638,8 @@ static ssize_t module_attr_show(struct kobject *kobj,
        if (!attribute->show)
                return -EIO;
 
-       if (!try_module_get(mk->mod))
-               return -ENODEV;
-
        ret = attribute->show(attribute, mk->mod, buf);
 
-       module_put(mk->mod);
-
        return ret;
 }
 
@@ -662,13 +657,8 @@ static ssize_t module_attr_store(struct kobject *kobj,
        if (!attribute->store)
                return -EIO;
 
-       if (!try_module_get(mk->mod))
-               return -ENODEV;
-
        ret = attribute->store(attribute, mk->mod, buf, len);
 
-       module_put(mk->mod);
-
        return ret;
 }
 
index 8cf15a5..fedf5e3 100644 (file)
@@ -609,7 +609,7 @@ module_param(qlowmark, int, 0);
 module_param(rsinterval, int, 0);
 #endif
 EXPORT_SYMBOL_GPL(rcu_batches_completed);
-EXPORT_SYMBOL(call_rcu);  /* WARNING: GPL-only in April 2006. */
-EXPORT_SYMBOL(call_rcu_bh);  /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(call_rcu);    /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(call_rcu_bh); /* WARNING: GPL-only in April 2006. */
 EXPORT_SYMBOL_GPL(synchronize_rcu);
-EXPORT_SYMBOL(synchronize_kernel);  /* WARNING: GPL-only in April 2006. */
+EXPORT_SYMBOL_GPL_FUTURE(synchronize_kernel); /* WARNING: GPL-only in April 2006. */
index efe67fa..25204a4 100644 (file)
@@ -194,6 +194,17 @@ int kobject_add(struct kobject * kobj)
                unlink(kobj);
                if (parent)
                        kobject_put(parent);
+
+               /* be noisy on error issues */
+               if (error == -EEXIST)
+                       printk("kobject_add failed for %s with -EEXIST, "
+                              "don't try to register things with the "
+                              "same name in the same directory.\n",
+                              kobject_name(kobj));
+               else
+                       printk("kobject_add failed for %s (%d)\n",
+                              kobject_name(kobj), error);
+               dump_stack();
        }
 
        return error;
@@ -207,18 +218,13 @@ int kobject_add(struct kobject * kobj)
 
 int kobject_register(struct kobject * kobj)
 {
-       int error = 0;
+       int error = -EINVAL;
        if (kobj) {
                kobject_init(kobj);
                error = kobject_add(kobj);
-               if (error) {
-                       printk("kobject_register failed for %s (%d)\n",
-                              kobject_name(kobj),error);
-                       dump_stack();
-               } else
+               if (!error)
                        kobject_uevent(kobj, KOBJ_ADD);
-       } else
-               error = -EINVAL;
+       }
        return error;
 }
 
@@ -379,6 +385,44 @@ void kobject_put(struct kobject * kobj)
 }
 
 
+static void dir_release(struct kobject *kobj)
+{
+       kfree(kobj);
+}
+
+static struct kobj_type dir_ktype = {
+       .release        = dir_release,
+       .sysfs_ops      = NULL,
+       .default_attrs  = NULL,
+};
+
+/**
+ *     kobject_add_dir - add sub directory of object.
+ *     @parent:        object in which a directory is created.
+ *     @name:  directory name.
+ *
+ *     Add a plain directory object as child of given object.
+ */
+struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+{
+       struct kobject *k;
+
+       if (!parent)
+               return NULL;
+
+       k = kzalloc(sizeof(*k), GFP_KERNEL);
+       if (!k)
+               return NULL;
+
+       k->parent = parent;
+       k->ktype = &dir_ktype;
+       kobject_set_name(k, name);
+       kobject_register(k);
+
+       return k;
+}
+EXPORT_SYMBOL_GPL(kobject_add_dir);
+
 /**
  *     kset_init - initialize a kset for use
  *     @k:     kset 
index 086a0c6..982226d 100644 (file)
@@ -26,6 +26,8 @@
 #define NUM_ENVP       32      /* number of env pointers */
 
 #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
+u64 uevent_seqnum;
+char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
 static DEFINE_SPINLOCK(sequence_lock);
 static struct sock *uevent_sock;
 
index 0d07cc3..4a467fa 100644 (file)
@@ -52,7 +52,12 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref))
        WARN_ON(release == NULL);
        WARN_ON(release == (void (*)(struct kref *))kfree);
 
-       if (atomic_dec_and_test(&kref->refcount)) {
+       /*
+        * if current count is one, we are the last user and can release object
+        * right now, avoiding an atomic operation on 'refcount'
+        */
+       if ((atomic_read(&kref->refcount) == 1) ||
+           (atomic_dec_and_test(&kref->refcount))) {
                release(kref);
                return 1;
        }
index 34e4296..270b9d2 100644 (file)
@@ -59,10 +59,8 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
        proto = find_snap_client(skb->h.raw);
        if (proto) {
                /* Pass the frame on. */
-               u8 *hdr = skb->data;
                skb->h.raw  += 5;
-               skb_pull(skb, 5);
-               skb_postpull_rcsum(skb, hdr, 5);
+               skb_pull_rcsum(skb, 5);
                rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
        } else {
                skb->sk = NULL;
index fa76220..3948949 100644 (file)
@@ -69,7 +69,7 @@ static struct packet_type vlan_packet_type = {
 
 /* Bits of netdev state that are propagated from real device to virtual */
 #define VLAN_LINK_STATE_MASK \
-       ((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER))
+       ((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER)|(1<<__LINK_STATE_DORMANT))
 
 /* End of global variables definitions. */
 
@@ -344,6 +344,26 @@ static void vlan_setup(struct net_device *new_dev)
        new_dev->do_ioctl = vlan_dev_ioctl;
 }
 
+static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev)
+{
+       /* Have to respect userspace enforced dormant state
+        * of real device, also must allow supplicant running
+        * on VLAN device
+        */
+       if (dev->operstate == IF_OPER_DORMANT)
+               netif_dormant_on(vlandev);
+       else
+               netif_dormant_off(vlandev);
+
+       if (netif_carrier_ok(dev)) {
+               if (!netif_carrier_ok(vlandev))
+                       netif_carrier_on(vlandev);
+       } else {
+               if (netif_carrier_ok(vlandev))
+                       netif_carrier_off(vlandev);
+       }
+}
+
 /*  Attach a VLAN device to a mac address (ie Ethernet Card).
  *  Returns the device that was created, or NULL if there was
  *  an error of some kind.
@@ -450,7 +470,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
        new_dev->flags = real_dev->flags;
        new_dev->flags &= ~IFF_UP;
 
-       new_dev->state = real_dev->state & VLAN_LINK_STATE_MASK;
+       new_dev->state = real_dev->state & ~(1<<__LINK_STATE_START);
 
        /* need 4 bytes for extra VLAN header info,
         * hope the underlying device can handle it.
@@ -498,6 +518,10 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
        if (register_netdevice(new_dev))
                goto out_free_newdev;
 
+       new_dev->iflink = real_dev->ifindex;
+       vlan_transfer_operstate(real_dev, new_dev);
+       linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */
+
        /* So, got the sucker initialized, now lets place
         * it into our local structure.
         */
@@ -573,25 +597,12 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
        switch (event) {
        case NETDEV_CHANGE:
                /* Propagate real device state to vlan devices */
-               flgs = dev->state & VLAN_LINK_STATE_MASK;
                for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
                        vlandev = grp->vlan_devices[i];
                        if (!vlandev)
                                continue;
 
-                       if (netif_carrier_ok(dev)) {
-                               if (!netif_carrier_ok(vlandev))
-                                       netif_carrier_on(vlandev);
-                       } else {
-                               if (netif_carrier_ok(vlandev))
-                                       netif_carrier_off(vlandev);
-                       }
-
-                       if ((vlandev->state & VLAN_LINK_STATE_MASK) != flgs) {
-                               vlandev->state = (vlandev->state &~ VLAN_LINK_STATE_MASK) 
-                                       | flgs;
-                               netdev_state_change(vlandev);
-                       }
+                       vlan_transfer_operstate(dev, vlandev);
                }
                break;
 
index 0f604d2..da9cfe9 100644 (file)
@@ -163,10 +163,8 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
        stats->rx_packets++;
        stats->rx_bytes += skb->len;
 
-       skb_pull(skb, VLAN_HLEN); /* take off the VLAN header (4 bytes currently) */
-
-       /* Need to correct hardware checksum */
-       skb_postpull_rcsum(skb, vhdr, VLAN_HLEN);
+       /* Take off the VLAN header (4 bytes currently) */
+       skb_pull_rcsum(skb, VLAN_HLEN);
 
        /* Ok, lets check to make sure the device (dev) we
         * came in on is what this VLAN is attached to.
index 73370de..3ab4e79 100644 (file)
@@ -289,7 +289,6 @@ static void clip_neigh_error(struct neighbour *neigh,struct sk_buff *skb)
 
 static struct neigh_ops clip_neigh_ops = {
        .family =               AF_INET,
-       .destructor =           clip_neigh_destroy,
        .solicit =              clip_neigh_solicit,
        .error_report =         clip_neigh_error,
        .output =               dev_queue_xmit,
@@ -347,6 +346,7 @@ static struct neigh_table clip_tbl = {
        /* parameters are copied from ARP ... */
        .parms = {
                .tbl                    = &clip_tbl,
+               .neigh_destructor       = clip_neigh_destroy,
                .base_reachable_time    = 30 * HZ,
                .retrans_time           = 1 * HZ,
                .gc_staletime           = 60 * HZ,
index 6656b11..ae00222 100644 (file)
@@ -451,12 +451,12 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
                dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf);
        } else {
                dev = NULL;
-               down(&atm_dev_mutex);
+               mutex_lock(&atm_dev_mutex);
                if (!list_empty(&atm_devs)) {
                        dev = list_entry(atm_devs.next, struct atm_dev, dev_list);
                        atm_dev_hold(dev);
                }
-               up(&atm_dev_mutex);
+               mutex_unlock(&atm_dev_mutex);
        }
        if (!dev)
                return -ENODEV;
index eb109af..851cfa6 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/atmmpc.h>
 #include <net/atmclip.h>
 #include <linux/atmlec.h>
+#include <linux/mutex.h>
 #include <asm/ioctls.h>
 
 #include "resources.h"
 #include "common.h"
 
 
-static DECLARE_MUTEX(ioctl_mutex);
+static DEFINE_MUTEX(ioctl_mutex);
 static LIST_HEAD(ioctl_list);
 
 
 void register_atm_ioctl(struct atm_ioctl *ioctl)
 {
-       down(&ioctl_mutex);
+       mutex_lock(&ioctl_mutex);
        list_add_tail(&ioctl->list, &ioctl_list);
-       up(&ioctl_mutex);
+       mutex_unlock(&ioctl_mutex);
 }
 
 void deregister_atm_ioctl(struct atm_ioctl *ioctl)
 {
-       down(&ioctl_mutex);
+       mutex_lock(&ioctl_mutex);
        list_del(&ioctl->list);
-       up(&ioctl_mutex);
+       mutex_unlock(&ioctl_mutex);
 }
 
 EXPORT_SYMBOL(register_atm_ioctl);
@@ -137,7 +138,7 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
        error = -ENOIOCTLCMD;
 
-       down(&ioctl_mutex);
+       mutex_lock(&ioctl_mutex);
        list_for_each(pos, &ioctl_list) {
                struct atm_ioctl * ic = list_entry(pos, struct atm_ioctl, list);
                if (try_module_get(ic->owner)) {
@@ -147,7 +148,7 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                                break;
                }
        }
-       up(&ioctl_mutex);
+       mutex_unlock(&ioctl_mutex);
 
        if (error != -ENOIOCTLCMD)
                goto done;
index 2241905..18ac806 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/bitops.h>
 #include <linux/capability.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
+
 #include <net/sock.h>   /* for struct sock */
 
 #include "common.h"
@@ -26,7 +28,7 @@
 
 
 LIST_HEAD(atm_devs);
-DECLARE_MUTEX(atm_dev_mutex);
+DEFINE_MUTEX(atm_dev_mutex);
 
 static struct atm_dev *__alloc_atm_dev(const char *type)
 {
@@ -65,9 +67,9 @@ struct atm_dev *atm_dev_lookup(int number)
 {
        struct atm_dev *dev;
 
-       down(&atm_dev_mutex);
+       mutex_lock(&atm_dev_mutex);
        dev = __atm_dev_lookup(number);
-       up(&atm_dev_mutex);
+       mutex_unlock(&atm_dev_mutex);
        return dev;
 }
 
@@ -83,11 +85,11 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
                    type);
                return NULL;
        }
-       down(&atm_dev_mutex);
+       mutex_lock(&atm_dev_mutex);
        if (number != -1) {
                if ((inuse = __atm_dev_lookup(number))) {
                        atm_dev_put(inuse);
-                       up(&atm_dev_mutex);
+                       mutex_unlock(&atm_dev_mutex);
                        kfree(dev);
                        return NULL;
                }
@@ -112,12 +114,12 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
                printk(KERN_ERR "atm_dev_register: "
                       "atm_proc_dev_register failed for dev %s\n",
                       type);
-               up(&atm_dev_mutex);
+               mutex_unlock(&atm_dev_mutex);
                kfree(dev);
                return NULL;
        }
        list_add_tail(&dev->dev_list, &atm_devs);
-       up(&atm_dev_mutex);
+       mutex_unlock(&atm_dev_mutex);
 
        return dev;
 }
@@ -133,9 +135,9 @@ void atm_dev_deregister(struct atm_dev *dev)
         * with same number can appear, such we need deregister proc, 
         * release async all vccs and remove them from vccs list too
         */
-       down(&atm_dev_mutex);
+       mutex_lock(&atm_dev_mutex);
        list_del(&dev->dev_list);
-       up(&atm_dev_mutex);
+       mutex_unlock(&atm_dev_mutex);
 
        atm_dev_release_vccs(dev);
        atm_proc_dev_deregister(dev);
@@ -196,16 +198,16 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg)
                                return -EFAULT;
                        if (get_user(len, &iobuf->length))
                                return -EFAULT;
-                       down(&atm_dev_mutex);
+                       mutex_lock(&atm_dev_mutex);
                        list_for_each(p, &atm_devs)
                                size += sizeof(int);
                        if (size > len) {
-                               up(&atm_dev_mutex);
+                               mutex_unlock(&atm_dev_mutex);
                                return -E2BIG;
                        }
                        tmp_buf = kmalloc(size, GFP_ATOMIC);
                        if (!tmp_buf) {
-                               up(&atm_dev_mutex);
+                               mutex_unlock(&atm_dev_mutex);
                                return -ENOMEM;
                        }
                        tmp_p = tmp_buf;
@@ -213,7 +215,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg)
                                dev = list_entry(p, struct atm_dev, dev_list);
                                *tmp_p++ = dev->number;
                        }
-                       up(&atm_dev_mutex);
+                       mutex_unlock(&atm_dev_mutex);
                        error = ((copy_to_user(buf, tmp_buf, size)) ||
                                        put_user(size, &iobuf->length))
                                                ? -EFAULT : 0;
@@ -400,13 +402,13 @@ static __inline__ void *dev_get_idx(loff_t left)
 
 void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       down(&atm_dev_mutex);
+       mutex_lock(&atm_dev_mutex);
        return *pos ? dev_get_idx(*pos) : (void *) 1;
 }
 
 void atm_dev_seq_stop(struct seq_file *seq, void *v)
 {
-       up(&atm_dev_mutex);
+       mutex_unlock(&atm_dev_mutex);
 }
  
 void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
index b7fb82a..ac7222f 100644 (file)
@@ -8,10 +8,11 @@
 
 #include <linux/config.h>
 #include <linux/atmdev.h>
+#include <linux/mutex.h>
 
 
 extern struct list_head atm_devs;
-extern struct semaphore atm_dev_mutex;
+extern struct mutex atm_dev_mutex;
 
 int atm_dev_ioctl(unsigned int cmd, void __user *arg);
 
index 5b4253c..e99010c 100644 (file)
@@ -37,6 +37,8 @@
 #include <linux/wait.h>
 #include <linux/device.h>
 #include <linux/net.h>
+#include <linux/mutex.h>
+
 #include <net/sock.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
@@ -57,9 +59,9 @@ static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU;
 
 static struct task_struct *rfcomm_thread;
 
-static DECLARE_MUTEX(rfcomm_sem);
-#define rfcomm_lock()  down(&rfcomm_sem);
-#define rfcomm_unlock()        up(&rfcomm_sem);
+static DEFINE_MUTEX(rfcomm_mutex);
+#define rfcomm_lock()  mutex_lock(&rfcomm_mutex)
+#define rfcomm_unlock()        mutex_unlock(&rfcomm_mutex)
 
 static unsigned long rfcomm_event;
 
index db23d59..12265af 100644 (file)
@@ -4,6 +4,7 @@
 
 config BRIDGE
        tristate "802.1d Ethernet Bridging"
+       select LLC
        ---help---
          If you say Y here, then your Linux box will be able to act as an
          Ethernet bridge, which means that the different Ethernet segments it
index 188cc1a..22d806c 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/llc.h>
+#include <net/llc.h>
 
 #include "br_private.h"
 
 int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
 
+static struct llc_sap *br_stp_sap;
+
 static int __init br_init(void)
 {
+       br_stp_sap = llc_sap_open(LLC_SAP_BSPAN, br_stp_rcv);
+       if (!br_stp_sap) {
+               printk(KERN_ERR "bridge: can't register sap for STP\n");
+               return -EBUSY;
+       }
+
        br_fdb_init();
 
 #ifdef CONFIG_BRIDGE_NETFILTER
@@ -45,6 +55,8 @@ static int __init br_init(void)
 
 static void __exit br_deinit(void)
 {
+       llc_sap_close(br_stp_sap);
+
 #ifdef CONFIG_BRIDGE_NETFILTER
        br_netfilter_fini();
 #endif
index 0b33a7b..0c88a2a 100644 (file)
@@ -27,6 +27,7 @@ static struct net_device_stats *br_dev_get_stats(struct net_device *dev)
        return &br->statistics;
 }
 
+/* net device transmit always called with no BH (preempt_disabled) */
 int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct net_bridge *br = netdev_priv(dev);
@@ -39,7 +40,6 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        skb->mac.raw = skb->data;
        skb_pull(skb, ETH_HLEN);
 
-       rcu_read_lock();
        if (dest[0] & 1) 
                br_flood_deliver(br, skb, 0);
        else if ((dst = __br_fdb_get(br, dest)) != NULL)
@@ -47,7 +47,6 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        else
                br_flood_deliver(br, skb, 0);
 
-       rcu_read_unlock();
        return 0;
 }
 
index 1f08a59..3a73b8c 100644 (file)
@@ -341,7 +341,6 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
        if (hold_time(br) == 0)
                return;
 
-       rcu_read_lock();
        fdb = fdb_find(head, addr);
        if (likely(fdb)) {
                /* attempt to update an entry for a local interface */
@@ -356,13 +355,12 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
                        fdb->ageing_timer = jiffies;
                }
        } else {
-               spin_lock_bh(&br->hash_lock);
+               spin_lock(&br->hash_lock);
                if (!fdb_find(head, addr))
                        fdb_create(head, source, addr, 0);
                /* else  we lose race and someone else inserts
                 * it first, don't bother updating
                 */
-               spin_unlock_bh(&br->hash_lock);
+               spin_unlock(&br->hash_lock);
        }
-       rcu_read_unlock();
 }
index f36b35e..59eef42 100644 (file)
@@ -210,7 +210,8 @@ static struct net_device *new_bridge_dev(const char *name)
 
        br->bridge_id.prio[0] = 0x80;
        br->bridge_id.prio[1] = 0x00;
-       memset(br->bridge_id.addr, 0, ETH_ALEN);
+
+       memcpy(br->group_addr, br_group_address, ETH_ALEN);
 
        br->feature_mask = dev->features;
        br->stp_enabled = 0;
@@ -237,12 +238,11 @@ static int find_portno(struct net_bridge *br)
        struct net_bridge_port *p;
        unsigned long *inuse;
 
-       inuse = kmalloc(BITS_TO_LONGS(BR_MAX_PORTS)*sizeof(unsigned long),
+       inuse = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long),
                        GFP_KERNEL);
        if (!inuse)
                return -ENOMEM;
 
-       memset(inuse, 0, BITS_TO_LONGS(BR_MAX_PORTS)*sizeof(unsigned long));
        set_bit(0, inuse);      /* zero is reserved */
        list_for_each_entry(p, &br->port_list, list) {
                set_bit(p->port_no, inuse);
@@ -264,11 +264,10 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
        if (index < 0)
                return ERR_PTR(index);
 
-       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (p == NULL)
                return ERR_PTR(-ENOMEM);
 
-       memset(p, 0, sizeof(*p));
        p->br = br;
        dev_hold(dev);
        p->dev = dev;
index 4eef837..b776656 100644 (file)
 #include <linux/netfilter_bridge.h>
 #include "br_private.h"
 
-const unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
-
-static int br_pass_frame_up_finish(struct sk_buff *skb)
-{
-       netif_receive_skb(skb);
-       return 0;
-}
+/* Bridge group multicast address 802.1d (pg 51). */
+const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 
 static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
 {
@@ -38,7 +33,7 @@ static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
        skb->dev = br->dev;
 
        NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
-                       br_pass_frame_up_finish);
+               netif_receive_skb);
 }
 
 /* note: already called with rcu_read_lock (preempt_disabled) */
@@ -100,6 +95,25 @@ drop:
        goto out;
 }
 
+/* note: already called with rcu_read_lock (preempt_disabled) */
+static int br_handle_local_finish(struct sk_buff *skb)
+{
+       struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
+
+       if (p && p->state != BR_STATE_DISABLED)
+               br_fdb_update(p->br, p, eth_hdr(skb)->h_source);
+
+       return 0;        /* process further */
+}
+
+/* Does address match the link local multicast address.
+ * 01:80:c2:00:00:0X
+ */
+static inline int is_link_local(const unsigned char *dest)
+{
+       return memcmp(dest, br_group_address, 5) == 0 && (dest[5] & 0xf0) == 0;
+}
+
 /*
  * Called via br_handle_frame_hook.
  * Return 0 if *pskb should be processed furthur
@@ -117,15 +131,10 @@ int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb)
        if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
                goto err;
 
-       if (p->br->stp_enabled &&
-           !memcmp(dest, bridge_ula, 5) &&
-           !(dest[5] & 0xF0)) {
-               if (!dest[5]) {
-                       NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, 
-                               NULL, br_stp_handle_bpdu);
-                       return 1;
-               }
-               goto err;
+       if (unlikely(is_link_local(dest))) {
+               skb->pkt_type = PACKET_HOST;
+               return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
+                              NULL, br_handle_local_finish) != 0;
        }
 
        if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) {
index e060aad..f29450b 100644 (file)
@@ -61,15 +61,25 @@ static int brnf_filter_vlan_tagged = 1;
 #define brnf_filter_vlan_tagged 1
 #endif
 
-#define IS_VLAN_IP (skb->protocol == __constant_htons(ETH_P_8021Q) &&    \
-       hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP) &&  \
-       brnf_filter_vlan_tagged)
-#define IS_VLAN_IPV6 (skb->protocol == __constant_htons(ETH_P_8021Q) &&    \
-       hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IPV6) &&  \
-       brnf_filter_vlan_tagged)
-#define IS_VLAN_ARP (skb->protocol == __constant_htons(ETH_P_8021Q) &&   \
-       hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_ARP) && \
-       brnf_filter_vlan_tagged)
+static __be16 inline vlan_proto(const struct sk_buff *skb)
+{
+       return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+}
+
+#define IS_VLAN_IP(skb) \
+       (skb->protocol == htons(ETH_P_8021Q) && \
+        vlan_proto(skb) == htons(ETH_P_IP) &&  \
+        brnf_filter_vlan_tagged)
+
+#define IS_VLAN_IPV6(skb) \
+       (skb->protocol == htons(ETH_P_8021Q) && \
+        vlan_proto(skb) == htons(ETH_P_IPV6) &&\
+        brnf_filter_vlan_tagged)
+
+#define IS_VLAN_ARP(skb) \
+       (skb->protocol == htons(ETH_P_8021Q) && \
+        vlan_proto(skb) == htons(ETH_P_ARP) && \
+        brnf_filter_vlan_tagged)
 
 /* We need these fake structures to make netfilter happy --
  * lots of places assume that skb->dst != NULL, which isn't
@@ -103,6 +113,25 @@ static inline struct net_device *bridge_parent(const struct net_device *dev)
        return port ? port->br->dev : NULL;
 }
 
+static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
+{
+       skb->nf_bridge = kzalloc(sizeof(struct nf_bridge_info), GFP_ATOMIC);
+       if (likely(skb->nf_bridge))
+               atomic_set(&(skb->nf_bridge->use), 1);
+
+       return skb->nf_bridge;
+}
+
+static inline void nf_bridge_save_header(struct sk_buff *skb)
+{
+        int header_size = 16;
+
+       if (skb->protocol == htons(ETH_P_8021Q))
+               header_size = 18;
+
+       memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
+}
+
 /* PF_BRIDGE/PRE_ROUTING *********************************************/
 /* Undo the changes made for ip6tables PREROUTING and continue the
  * bridge PRE_ROUTING hook. */
@@ -120,7 +149,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
        dst_hold(skb->dst);
 
        skb->dev = nf_bridge->physindev;
-       if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+       if (skb->protocol == htons(ETH_P_8021Q)) {
                skb_push(skb, VLAN_HLEN);
                skb->nh.raw -= VLAN_HLEN;
        }
@@ -136,7 +165,7 @@ static void __br_dnat_complain(void)
 
        if (jiffies - last_complaint >= 5 * HZ) {
                printk(KERN_WARNING "Performing cross-bridge DNAT requires IP "
-                       "forwarding to be enabled\n");
+                      "forwarding to be enabled\n");
                last_complaint = jiffies;
        }
 }
@@ -196,7 +225,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
        if (!skb->dev)
                kfree_skb(skb);
        else {
-               if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+               if (skb->protocol == htons(ETH_P_8021Q)) {
                        skb_pull(skb, VLAN_HLEN);
                        skb->nh.raw += VLAN_HLEN;
                }
@@ -218,12 +247,17 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
        nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
 
        if (dnat_took_place(skb)) {
-               if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
-                   dev)) {
+               if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev)) {
                        struct rtable *rt;
-                       struct flowi fl = { .nl_u = 
-                       { .ip4_u = { .daddr = iph->daddr, .saddr = 0 ,
-                                    .tos = RT_TOS(iph->tos)} }, .proto = 0};
+                       struct flowi fl = {
+                               .nl_u = {
+                                       .ip4_u = {
+                                                .daddr = iph->daddr,
+                                                .saddr = 0,
+                                                .tos = RT_TOS(iph->tos) },
+                               },
+                               .proto = 0,
+                       };
 
                        if (!ip_route_output_key(&rt, &fl)) {
                                /* - Bridged-and-DNAT'ed traffic doesn't
@@ -247,7 +281,7 @@ bridged_dnat:
                                nf_bridge->mask |= BRNF_BRIDGED_DNAT;
                                skb->dev = nf_bridge->physindev;
                                if (skb->protocol ==
-                                   __constant_htons(ETH_P_8021Q)) {
+                                   htons(ETH_P_8021Q)) {
                                        skb_push(skb, VLAN_HLEN);
                                        skb->nh.raw -= VLAN_HLEN;
                                }
@@ -257,8 +291,7 @@ bridged_dnat:
                                               1);
                                return 0;
                        }
-                       memcpy(eth_hdr(skb)->h_dest, dev->dev_addr,
-                              ETH_ALEN);
+                       memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
                        skb->pkt_type = PACKET_HOST;
                }
        } else {
@@ -267,7 +300,7 @@ bridged_dnat:
        }
 
        skb->dev = nf_bridge->physindev;
-       if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+       if (skb->protocol == htons(ETH_P_8021Q)) {
                skb_push(skb, VLAN_HLEN);
                skb->nh.raw -= VLAN_HLEN;
        }
@@ -297,10 +330,10 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb)
 /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */
 static int check_hbh_len(struct sk_buff *skb)
 {
-       unsigned char *raw = (u8*)(skb->nh.ipv6h+1);
+       unsigned char *raw = (u8 *) (skb->nh.ipv6h + 1);
        u32 pkt_len;
        int off = raw - skb->nh.raw;
-       int len = (raw[1]+1)<<3;
+       int len = (raw[1] + 1) << 3;
 
        if ((raw + len) - skb->data > skb_headlen(skb))
                goto bad;
@@ -309,7 +342,7 @@ static int check_hbh_len(struct sk_buff *skb)
        len -= 2;
 
        while (len > 0) {
-               int optlen = skb->nh.raw[off+1]+2;
+               int optlen = skb->nh.raw[off + 1] + 2;
 
                switch (skb->nh.raw[off]) {
                case IPV6_TLV_PAD0:
@@ -320,16 +353,16 @@ static int check_hbh_len(struct sk_buff *skb)
                        break;
 
                case IPV6_TLV_JUMBO:
-                       if (skb->nh.raw[off+1] != 4 || (off&3) != 2)
+                       if (skb->nh.raw[off + 1] != 4 || (off & 3) != 2)
                                goto bad;
-                       pkt_len = ntohl(*(u32*)(skb->nh.raw+off+2));
+                       pkt_len = ntohl(*(u32 *) (skb->nh.raw + off + 2));
                        if (pkt_len <= IPV6_MAXPLEN ||
                            skb->nh.ipv6h->payload_len)
                                goto bad;
                        if (pkt_len > skb->len - sizeof(struct ipv6hdr))
                                goto bad;
                        if (pskb_trim_rcsum(skb,
-                           pkt_len+sizeof(struct ipv6hdr)))
+                                           pkt_len + sizeof(struct ipv6hdr)))
                                goto bad;
                        break;
                default:
@@ -350,12 +383,13 @@ bad:
 /* Replicate the checks that IPv6 does on packet reception and pass the packet
  * to ip6tables, which doesn't support NAT, so things are fairly simple. */
 static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
-   struct sk_buff *skb, const struct net_device *in,
-   const struct net_device *out, int (*okfn)(struct sk_buff *))
+                                          struct sk_buff *skb,
+                                          const struct net_device *in,
+                                          const struct net_device *out,
+                                          int (*okfn)(struct sk_buff *))
 {
        struct ipv6hdr *hdr;
        u32 pkt_len;
-       struct nf_bridge_info *nf_bridge;
 
        if (skb->len < sizeof(struct ipv6hdr))
                goto inhdr_error;
@@ -381,10 +415,10 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
                }
        }
        if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb))
-                       goto inhdr_error;
+               goto inhdr_error;
 
-       nf_bridge_put(skb->nf_bridge);
-       if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
+       nf_bridge_put(skb->nf_bridge);
+       if (!nf_bridge_alloc(skb))
                return NF_DROP;
        if (!setup_pre_routing(skb))
                return NF_DROP;
@@ -412,10 +446,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
        struct iphdr *iph;
        __u32 len;
        struct sk_buff *skb = *pskb;
-       struct nf_bridge_info *nf_bridge;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(*pskb);
 
-       if (skb->protocol == __constant_htons(ETH_P_IPV6) || IS_VLAN_IPV6) {
+       if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb)) {
 #ifdef CONFIG_SYSCTL
                if (!brnf_call_ip6tables)
                        return NF_ACCEPT;
@@ -423,10 +455,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
                if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
                        goto out;
 
-               if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-                       u8 *vhdr = skb->data;
-                       skb_pull(skb, VLAN_HLEN);
-                       skb_postpull_rcsum(skb, vhdr, VLAN_HLEN);
+               if (skb->protocol == htons(ETH_P_8021Q)) {
+                       skb_pull_rcsum(skb, VLAN_HLEN);
                        skb->nh.raw += VLAN_HLEN;
                }
                return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
@@ -436,16 +466,14 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
                return NF_ACCEPT;
 #endif
 
-       if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
+       if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb))
                return NF_ACCEPT;
 
        if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
                goto out;
 
-       if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-               u8 *vhdr = skb->data;
-               skb_pull(skb, VLAN_HLEN);
-               skb_postpull_rcsum(skb, vhdr, VLAN_HLEN);
+       if (skb->protocol == htons(ETH_P_8021Q)) {
+               skb_pull_rcsum(skb, VLAN_HLEN);
                skb->nh.raw += VLAN_HLEN;
        }
 
@@ -456,15 +484,15 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
        if (iph->ihl < 5 || iph->version != 4)
                goto inhdr_error;
 
-       if (!pskb_may_pull(skb, 4*iph->ihl))
+       if (!pskb_may_pull(skb, 4 * iph->ihl))
                goto inhdr_error;
 
        iph = skb->nh.iph;
-       if (ip_fast_csum((__u8 *)iph, iph->ihl) != 0)
+       if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0)
                goto inhdr_error;
 
        len = ntohs(iph->tot_len);
-       if (skb->len < len || len < 4*iph->ihl)
+       if (skb->len < len || len < 4 * iph->ihl)
                goto inhdr_error;
 
        if (skb->len > len) {
@@ -473,8 +501,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
                        skb->ip_summed = CHECKSUM_NONE;
        }
 
-       nf_bridge_put(skb->nf_bridge);
-       if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
+       nf_bridge_put(skb->nf_bridge);
+       if (!nf_bridge_alloc(skb))
                return NF_DROP;
        if (!setup_pre_routing(skb))
                return NF_DROP;
@@ -486,7 +514,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
        return NF_STOLEN;
 
 inhdr_error:
-//     IP_INC_STATS_BH(IpInHdrErrors);
+//      IP_INC_STATS_BH(IpInHdrErrors);
 out:
        return NF_DROP;
 }
@@ -500,8 +528,9 @@ out:
  * register an IPv4 PRE_ROUTING 'sabotage' hook that will
  * prevent this from happening. */
 static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb,
-   const struct net_device *in, const struct net_device *out,
-   int (*okfn)(struct sk_buff *))
+                                  const struct net_device *in,
+                                  const struct net_device *out,
+                                  int (*okfn)(struct sk_buff *))
 {
        struct sk_buff *skb = *pskb;
 
@@ -513,15 +542,13 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb,
        return NF_ACCEPT;
 }
 
-
 /* PF_BRIDGE/FORWARD *************************************************/
 static int br_nf_forward_finish(struct sk_buff *skb)
 {
        struct nf_bridge_info *nf_bridge = skb->nf_bridge;
        struct net_device *in;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
 
-       if (skb->protocol != __constant_htons(ETH_P_ARP) && !IS_VLAN_ARP) {
+       if (skb->protocol != htons(ETH_P_ARP) && !IS_VLAN_ARP(skb)) {
                in = nf_bridge->physindev;
                if (nf_bridge->mask & BRNF_PKT_TYPE) {
                        skb->pkt_type = PACKET_OTHERHOST;
@@ -530,12 +557,12 @@ static int br_nf_forward_finish(struct sk_buff *skb)
        } else {
                in = *((struct net_device **)(skb->cb));
        }
-       if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+       if (skb->protocol == htons(ETH_P_8021Q)) {
                skb_push(skb, VLAN_HLEN);
                skb->nh.raw -= VLAN_HLEN;
        }
        NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
-                       skb->dev, br_forward_finish, 1);
+                      skb->dev, br_forward_finish, 1);
        return 0;
 }
 
@@ -545,12 +572,12 @@ static int br_nf_forward_finish(struct sk_buff *skb)
  * because of the physdev module. For ARP, indev and outdev are the
  * bridge ports. */
 static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
-   const struct net_device *in, const struct net_device *out,
-   int (*okfn)(struct sk_buff *))
+                                    const struct net_device *in,
+                                    const struct net_device *out,
+                                    int (*okfn)(struct sk_buff *))
 {
        struct sk_buff *skb = *pskb;
        struct nf_bridge_info *nf_bridge;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
        struct net_device *parent;
        int pf;
 
@@ -561,12 +588,12 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
        if (!parent)
                return NF_DROP;
 
-       if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
+       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
                pf = PF_INET;
        else
                pf = PF_INET6;
 
-       if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+       if (skb->protocol == htons(ETH_P_8021Q)) {
                skb_pull(*pskb, VLAN_HLEN);
                (*pskb)->nh.raw += VLAN_HLEN;
        }
@@ -588,11 +615,11 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
 }
 
 static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
-   const struct net_device *in, const struct net_device *out,
-   int (*okfn)(struct sk_buff *))
+                                     const struct net_device *in,
+                                     const struct net_device *out,
+                                     int (*okfn)(struct sk_buff *))
 {
        struct sk_buff *skb = *pskb;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
        struct net_device **d = (struct net_device **)(skb->cb);
 
 #ifdef CONFIG_SYSCTL
@@ -600,15 +627,15 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
                return NF_ACCEPT;
 #endif
 
-       if (skb->protocol != __constant_htons(ETH_P_ARP)) {
-               if (!IS_VLAN_ARP)
+       if (skb->protocol != htons(ETH_P_ARP)) {
+               if (!IS_VLAN_ARP(skb))
                        return NF_ACCEPT;
                skb_pull(*pskb, VLAN_HLEN);
                (*pskb)->nh.raw += VLAN_HLEN;
        }
 
        if (skb->nh.arph->ar_pln != 4) {
-               if (IS_VLAN_ARP) {
+               if (IS_VLAN_ARP(skb)) {
                        skb_push(*pskb, VLAN_HLEN);
                        (*pskb)->nh.raw -= VLAN_HLEN;
                }
@@ -621,17 +648,16 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
        return NF_STOLEN;
 }
 
-
 /* PF_BRIDGE/LOCAL_OUT ***********************************************/
 static int br_nf_local_out_finish(struct sk_buff *skb)
 {
-       if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+       if (skb->protocol == htons(ETH_P_8021Q)) {
                skb_push(skb, VLAN_HLEN);
                skb->nh.raw -= VLAN_HLEN;
        }
 
        NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
-                       br_forward_finish, NF_BR_PRI_FIRST + 1);
+                      br_forward_finish, NF_BR_PRI_FIRST + 1);
 
        return 0;
 }
@@ -657,19 +683,19 @@ static int br_nf_local_out_finish(struct sk_buff *skb)
  * even routed packets that didn't arrive on a bridge interface have their
  * nf_bridge->physindev set. */
 static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
-   const struct net_device *in, const struct net_device *out,
-   int (*okfn)(struct sk_buff *))
+                                   const struct net_device *in,
+                                   const struct net_device *out,
+                                   int (*okfn)(struct sk_buff *))
 {
        struct net_device *realindev, *realoutdev;
        struct sk_buff *skb = *pskb;
        struct nf_bridge_info *nf_bridge;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
        int pf;
 
        if (!skb->nf_bridge)
                return NF_ACCEPT;
 
-       if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
+       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
                pf = PF_INET;
        else
                pf = PF_INET6;
@@ -695,7 +721,7 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
                        skb->pkt_type = PACKET_OTHERHOST;
                        nf_bridge->mask ^= BRNF_PKT_TYPE;
                }
-               if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+               if (skb->protocol == htons(ETH_P_8021Q)) {
                        skb_push(skb, VLAN_HLEN);
                        skb->nh.raw -= VLAN_HLEN;
                }
@@ -713,14 +739,14 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
        if (nf_bridge->netoutdev)
                realoutdev = nf_bridge->netoutdev;
 #endif
-       if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+       if (skb->protocol == htons(ETH_P_8021Q)) {
                skb_pull(skb, VLAN_HLEN);
                (*pskb)->nh.raw += VLAN_HLEN;
        }
        /* IP forwarded traffic has a physindev, locally
         * generated traffic hasn't. */
        if (realindev != NULL) {
-               if (!(nf_bridge->mask & BRNF_DONT_TAKE_PARENT) ) {
+               if (!(nf_bridge->mask & BRNF_DONT_TAKE_PARENT)) {
                        struct net_device *parent = bridge_parent(realindev);
                        if (parent)
                                realindev = parent;
@@ -742,12 +768,12 @@ out:
 
 /* PF_BRIDGE/POST_ROUTING ********************************************/
 static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
-   const struct net_device *in, const struct net_device *out,
-   int (*okfn)(struct sk_buff *))
+                                      const struct net_device *in,
+                                      const struct net_device *out,
+                                      int (*okfn)(struct sk_buff *))
 {
        struct sk_buff *skb = *pskb;
        struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
        struct net_device *realoutdev = bridge_parent(skb->dev);
        int pf;
 
@@ -756,7 +782,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
         * keep the check just to be sure... */
        if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) {
                printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
-                                "bad mac.raw pointer.");
+                      "bad mac.raw pointer.");
                goto print_error;
        }
 #endif
@@ -767,7 +793,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
        if (!realoutdev)
                return NF_DROP;
 
-       if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
+       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
                pf = PF_INET;
        else
                pf = PF_INET6;
@@ -786,7 +812,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
                nf_bridge->mask |= BRNF_PKT_TYPE;
        }
 
-       if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
+       if (skb->protocol == htons(ETH_P_8021Q)) {
                skb_pull(skb, VLAN_HLEN);
                skb->nh.raw += VLAN_HLEN;
        }
@@ -798,7 +824,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
                realoutdev = nf_bridge->netoutdev;
 #endif
        NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev,
-               br_dev_queue_push_xmit);
+               br_dev_queue_push_xmit);
 
        return NF_STOLEN;
 
@@ -810,18 +836,18 @@ print_error:
                        printk("[%s]", realoutdev->name);
        }
        printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw,
-                                             skb->data);
+              skb->data);
        return NF_ACCEPT;
 #endif
 }
 
-
 /* IP/SABOTAGE *****************************************************/
 /* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING
  * for the second time. */
 static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb,
-   const struct net_device *in, const struct net_device *out,
-   int (*okfn)(struct sk_buff *))
+                                  const struct net_device *in,
+                                  const struct net_device *out,
+                                  int (*okfn)(struct sk_buff *))
 {
        if ((*pskb)->nf_bridge &&
            !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
@@ -835,18 +861,18 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb,
  * and PF_INET(6)/POST_ROUTING until we have done the forwarding
  * decision in the bridge code and have determined nf_bridge->physoutdev. */
 static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
-   const struct net_device *in, const struct net_device *out,
-   int (*okfn)(struct sk_buff *))
+                                   const struct net_device *in,
+                                   const struct net_device *out,
+                                   int (*okfn)(struct sk_buff *))
 {
        struct sk_buff *skb = *pskb;
 
        if ((out->hard_start_xmit == br_dev_xmit &&
-           okfn != br_nf_forward_finish &&
-           okfn != br_nf_local_out_finish &&
-           okfn != br_dev_queue_push_xmit)
+            okfn != br_nf_forward_finish &&
+            okfn != br_nf_local_out_finish && okfn != br_dev_queue_push_xmit)
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
            || ((out->priv_flags & IFF_802_1Q_VLAN) &&
-           VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit)
+               VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit)
 #endif
            ) {
                struct nf_bridge_info *nf_bridge;
@@ -971,8 +997,8 @@ static struct nf_hook_ops br_nf_ops[] = {
 
 #ifdef CONFIG_SYSCTL
 static
-int brnf_sysctl_call_tables(ctl_table *ctl, int write, struct file * filp,
-                       void __user *buffer, size_t *lenp, loff_t *ppos)
+int brnf_sysctl_call_tables(ctl_table * ctl, int write, struct file *filp,
+                           void __user * buffer, size_t * lenp, loff_t * ppos)
 {
        int ret;
 
@@ -1059,7 +1085,8 @@ int br_netfilter_init(void)
 #ifdef CONFIG_SYSCTL
        brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0);
        if (brnf_sysctl_header == NULL) {
-               printk(KERN_WARNING "br_netfilter: can't register to sysctl.\n");
+               printk(KERN_WARNING
+                      "br_netfilter: can't register to sysctl.\n");
                for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++)
                        nf_unregister_hook(&br_nf_ops[i]);
                return -EFAULT;
index 8f10e09..86ecea7 100644 (file)
@@ -109,6 +109,7 @@ struct net_bridge
        unsigned long                   bridge_hello_time;
        unsigned long                   bridge_forward_delay;
 
+       u8                              group_addr[ETH_ALEN];
        u16                             root_port;
        unsigned char                   stp_enabled;
        unsigned char                   topology_change;
@@ -122,7 +123,7 @@ struct net_bridge
 };
 
 extern struct notifier_block br_device_notifier;
-extern const unsigned char bridge_ula[6];
+extern const u8 br_group_address[ETH_ALEN];
 
 /* called under bridge lock */
 static inline int br_is_root_bridge(const struct net_bridge *br)
@@ -217,7 +218,8 @@ extern void br_stp_set_path_cost(struct net_bridge_port *p,
 extern ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id);
 
 /* br_stp_bpdu.c */
-extern int br_stp_handle_bpdu(struct sk_buff *skb);
+extern int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
+                     struct packet_type *pt, struct net_device *orig_dev);
 
 /* br_stp_timer.c */
 extern void br_stp_timer_init(struct net_bridge *br);
index 296f6a4..8934a54 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/netfilter_bridge.h>
+#include <linux/etherdevice.h>
+#include <linux/llc.h>
+#include <net/llc.h>
+#include <net/llc_pdu.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
 
-#define JIFFIES_TO_TICKS(j) (((j) << 8) / HZ)
-#define TICKS_TO_JIFFIES(j) (((j) * HZ) >> 8)
+#define STP_HZ         256
 
-static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int length)
+#define LLC_RESERVE sizeof(struct llc_pdu_un)
+
+static void br_send_bpdu(struct net_bridge_port *p,
+                        const unsigned char *data, int length)
 {
-       struct net_device *dev;
        struct sk_buff *skb;
-       int size;
 
        if (!p->br->stp_enabled)
                return;
 
-       size = length + 2*ETH_ALEN + 2;
-       if (size < 60)
-               size = 60;
-
-       dev = p->dev;
-
-       if ((skb = dev_alloc_skb(size)) == NULL) {
-               printk(KERN_INFO "br: memory squeeze!\n");
+       skb = dev_alloc_skb(length+LLC_RESERVE);
+       if (!skb)
                return;
-       }
 
-       skb->dev = dev;
+       skb->dev = p->dev;
        skb->protocol = htons(ETH_P_802_2);
-       skb->mac.raw = skb_put(skb, size);
-       memcpy(skb->mac.raw, bridge_ula, ETH_ALEN);
-       memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN);
-       skb->mac.raw[2*ETH_ALEN] = 0;
-       skb->mac.raw[2*ETH_ALEN+1] = length;
-       skb->nh.raw = skb->mac.raw + 2*ETH_ALEN + 2;
-       memcpy(skb->nh.raw, data, length);
-       memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2);
+
+       skb_reserve(skb, LLC_RESERVE);
+       memcpy(__skb_put(skb, length), data, length);
+
+       llc_pdu_header_init(skb, LLC_PDU_TYPE_U, LLC_SAP_BSPAN,
+                           LLC_SAP_BSPAN, LLC_PDU_CMD);
+       llc_pdu_init_as_ui_cmd(skb);
+
+       llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr);
 
        NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
                dev_queue_xmit);
 }
 
-static __inline__ void br_set_ticks(unsigned char *dest, int jiff)
+static inline void br_set_ticks(unsigned char *dest, int j)
 {
-       __u16 ticks;
+       unsigned long ticks = (STP_HZ * j)/ HZ;
 
-       ticks = JIFFIES_TO_TICKS(jiff);
-       dest[0] = (ticks >> 8) & 0xFF;
-       dest[1] = ticks & 0xFF;
+       *((__be16 *) dest) = htons(ticks);
 }
 
-static __inline__ int br_get_ticks(unsigned char *dest)
+static inline int br_get_ticks(const unsigned char *src)
 {
-       return TICKS_TO_JIFFIES((dest[0] << 8) | dest[1]);
+       unsigned long ticks = ntohs(*(__be16 *)src);
+
+       return (ticks * HZ + STP_HZ - 1) / STP_HZ;
 }
 
 /* called under bridge lock */
 void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
 {
-       unsigned char buf[38];
-
-       buf[0] = 0x42;
-       buf[1] = 0x42;
-       buf[2] = 0x03;
-       buf[3] = 0;
-       buf[4] = 0;
-       buf[5] = 0;
-       buf[6] = BPDU_TYPE_CONFIG;
-       buf[7] = (bpdu->topology_change ? 0x01 : 0) |
+       unsigned char buf[35];
+
+       buf[0] = 0;
+       buf[1] = 0;
+       buf[2] = 0;
+       buf[3] = BPDU_TYPE_CONFIG;
+       buf[4] = (bpdu->topology_change ? 0x01 : 0) |
                (bpdu->topology_change_ack ? 0x80 : 0);
-       buf[8] = bpdu->root.prio[0];
-       buf[9] = bpdu->root.prio[1];
-       buf[10] = bpdu->root.addr[0];
-       buf[11] = bpdu->root.addr[1];
-       buf[12] = bpdu->root.addr[2];
-       buf[13] = bpdu->root.addr[3];
-       buf[14] = bpdu->root.addr[4];
-       buf[15] = bpdu->root.addr[5];
-       buf[16] = (bpdu->root_path_cost >> 24) & 0xFF;
-       buf[17] = (bpdu->root_path_cost >> 16) & 0xFF;
-       buf[18] = (bpdu->root_path_cost >> 8) & 0xFF;
-       buf[19] = bpdu->root_path_cost & 0xFF;
-       buf[20] = bpdu->bridge_id.prio[0];
-       buf[21] = bpdu->bridge_id.prio[1];
-       buf[22] = bpdu->bridge_id.addr[0];
-       buf[23] = bpdu->bridge_id.addr[1];
-       buf[24] = bpdu->bridge_id.addr[2];
-       buf[25] = bpdu->bridge_id.addr[3];
-       buf[26] = bpdu->bridge_id.addr[4];
-       buf[27] = bpdu->bridge_id.addr[5];
-       buf[28] = (bpdu->port_id >> 8) & 0xFF;
-       buf[29] = bpdu->port_id & 0xFF;
-
-       br_set_ticks(buf+30, bpdu->message_age);
-       br_set_ticks(buf+32, bpdu->max_age);
-       br_set_ticks(buf+34, bpdu->hello_time);
-       br_set_ticks(buf+36, bpdu->forward_delay);
-
-       br_send_bpdu(p, buf, 38);
+       buf[5] = bpdu->root.prio[0];
+       buf[6] = bpdu->root.prio[1];
+       buf[7] = bpdu->root.addr[0];
+       buf[8] = bpdu->root.addr[1];
+       buf[9] = bpdu->root.addr[2];
+       buf[10] = bpdu->root.addr[3];
+       buf[11] = bpdu->root.addr[4];
+       buf[12] = bpdu->root.addr[5];
+       buf[13] = (bpdu->root_path_cost >> 24) & 0xFF;
+       buf[14] = (bpdu->root_path_cost >> 16) & 0xFF;
+       buf[15] = (bpdu->root_path_cost >> 8) & 0xFF;
+       buf[16] = bpdu->root_path_cost & 0xFF;
+       buf[17] = bpdu->bridge_id.prio[0];
+       buf[18] = bpdu->bridge_id.prio[1];
+       buf[19] = bpdu->bridge_id.addr[0];
+       buf[20] = bpdu->bridge_id.addr[1];
+       buf[21] = bpdu->bridge_id.addr[2];
+       buf[22] = bpdu->bridge_id.addr[3];
+       buf[23] = bpdu->bridge_id.addr[4];
+       buf[24] = bpdu->bridge_id.addr[5];
+       buf[25] = (bpdu->port_id >> 8) & 0xFF;
+       buf[26] = bpdu->port_id & 0xFF;
+
+       br_set_ticks(buf+27, bpdu->message_age);
+       br_set_ticks(buf+29, bpdu->max_age);
+       br_set_ticks(buf+31, bpdu->hello_time);
+       br_set_ticks(buf+33, bpdu->forward_delay);
+
+       br_send_bpdu(p, buf, 35);
 }
 
 /* called under bridge lock */
 void br_send_tcn_bpdu(struct net_bridge_port *p)
 {
-       unsigned char buf[7];
-
-       buf[0] = 0x42;
-       buf[1] = 0x42;
-       buf[2] = 0x03;
-       buf[3] = 0;
-       buf[4] = 0;
-       buf[5] = 0;
-       buf[6] = BPDU_TYPE_TCN;
+       unsigned char buf[4];
+
+       buf[0] = 0;
+       buf[1] = 0;
+       buf[2] = 0;
+       buf[3] = BPDU_TYPE_TCN;
        br_send_bpdu(p, buf, 7);
 }
 
-static const unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
-
-/* NO locks, but rcu_read_lock (preempt_disabled)  */
-int br_stp_handle_bpdu(struct sk_buff *skb)
+/*
+ * Called from llc.
+ *
+ * NO locks, but rcu_read_lock (preempt_disabled)
+ */
+int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
+              struct packet_type *pt, struct net_device *orig_dev)
 {
-       struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
+       const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
+       const unsigned char *dest = eth_hdr(skb)->h_dest;
+       struct net_bridge_port *p = rcu_dereference(dev->br_port);
        struct net_bridge *br;
-       unsigned char *buf;
+       const unsigned char *buf;
 
        if (!p)
                goto err;
 
-       br = p->br;
-       spin_lock(&br->lock);
+       if (pdu->ssap != LLC_SAP_BSPAN
+           || pdu->dsap != LLC_SAP_BSPAN
+           || pdu->ctrl_1 != LLC_PDU_TYPE_U)
+               goto err;
 
-       if (p->state == BR_STATE_DISABLED || !(br->dev->flags & IFF_UP))
-               goto out;
+       if (!pskb_may_pull(skb, 4))
+               goto err;
+
+       /* compare of protocol id and version */
+       buf = skb->data;
+       if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0)
+               goto err;
 
-       /* insert into forwarding database after filtering to avoid spoofing */
-       br_fdb_update(br, p, eth_hdr(skb)->h_source);
+       br = p->br;
+       spin_lock(&br->lock);
 
-       if (!br->stp_enabled)
+       if (p->state == BR_STATE_DISABLED
+           || !br->stp_enabled
+           || !(br->dev->flags & IFF_UP))
                goto out;
 
-       /* need at least the 802 and STP headers */
-       if (!pskb_may_pull(skb, sizeof(header)+1) ||
-           memcmp(skb->data, header, sizeof(header)))
+       if (compare_ether_addr(dest, br->group_addr) != 0)
                goto out;
 
-       buf = skb_pull(skb, sizeof(header));
+       buf = skb_pull(skb, 3);
 
        if (buf[0] == BPDU_TYPE_CONFIG) {
                struct br_config_bpdu bpdu;
 
                if (!pskb_may_pull(skb, 32))
-                   goto out;
+                       goto out;
 
                buf = skb->data;
                bpdu.topology_change = (buf[1] & 0x01) ? 1 : 0;
index 9bef55f..d0fcde8 100644 (file)
@@ -39,13 +39,13 @@ static void br_hello_timer_expired(unsigned long arg)
        struct net_bridge *br = (struct net_bridge *)arg;
        
        pr_debug("%s: hello timer expired\n", br->dev->name);
-       spin_lock_bh(&br->lock);
+       spin_lock(&br->lock);
        if (br->dev->flags & IFF_UP) {
                br_config_bpdu_generation(br);
 
                mod_timer(&br->hello_timer, jiffies + br->hello_time);
        }
-       spin_unlock_bh(&br->lock);
+       spin_unlock(&br->lock);
 }
 
 static void br_message_age_timer_expired(unsigned long arg)
@@ -71,7 +71,7 @@ static void br_message_age_timer_expired(unsigned long arg)
         * running when we are the root bridge. So..  this was_root
         * check is redundant. I'm leaving it in for now, though.
         */
-       spin_lock_bh(&br->lock);
+       spin_lock(&br->lock);
        if (p->state == BR_STATE_DISABLED)
                goto unlock;
        was_root = br_is_root_bridge(br);
@@ -82,7 +82,7 @@ static void br_message_age_timer_expired(unsigned long arg)
        if (br_is_root_bridge(br) && !was_root)
                br_become_root_bridge(br);
  unlock:
-       spin_unlock_bh(&br->lock);
+       spin_unlock(&br->lock);
 }
 
 static void br_forward_delay_timer_expired(unsigned long arg)
@@ -92,7 +92,7 @@ static void br_forward_delay_timer_expired(unsigned long arg)
 
        pr_debug("%s: %d(%s) forward delay timer\n",
                 br->dev->name, p->port_no, p->dev->name);
-       spin_lock_bh(&br->lock);
+       spin_lock(&br->lock);
        if (p->state == BR_STATE_LISTENING) {
                p->state = BR_STATE_LEARNING;
                mod_timer(&p->forward_delay_timer,
@@ -103,7 +103,7 @@ static void br_forward_delay_timer_expired(unsigned long arg)
                        br_topology_change_detection(br);
        }
        br_log_state(p);
-       spin_unlock_bh(&br->lock);
+       spin_unlock(&br->lock);
 }
 
 static void br_tcn_timer_expired(unsigned long arg)
@@ -111,13 +111,13 @@ static void br_tcn_timer_expired(unsigned long arg)
        struct net_bridge *br = (struct net_bridge *) arg;
 
        pr_debug("%s: tcn timer expired\n", br->dev->name);
-       spin_lock_bh(&br->lock);
+       spin_lock(&br->lock);
        if (br->dev->flags & IFF_UP) {
                br_transmit_tcn(br);
        
                mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time);
        }
-       spin_unlock_bh(&br->lock);
+       spin_unlock(&br->lock);
 }
 
 static void br_topology_change_timer_expired(unsigned long arg)
@@ -125,10 +125,10 @@ static void br_topology_change_timer_expired(unsigned long arg)
        struct net_bridge *br = (struct net_bridge *) arg;
 
        pr_debug("%s: topo change timer expired\n", br->dev->name);
-       spin_lock_bh(&br->lock);
+       spin_lock(&br->lock);
        br->topology_change_detected = 0;
        br->topology_change = 0;
-       spin_unlock_bh(&br->lock);
+       spin_unlock(&br->lock);
 }
 
 static void br_hold_timer_expired(unsigned long arg)
@@ -138,45 +138,36 @@ static void br_hold_timer_expired(unsigned long arg)
        pr_debug("%s: %d(%s) hold timer expired\n", 
                 p->br->dev->name,  p->port_no, p->dev->name);
 
-       spin_lock_bh(&p->br->lock);
+       spin_lock(&p->br->lock);
        if (p->config_pending)
                br_transmit_config(p);
-       spin_unlock_bh(&p->br->lock);
-}
-
-static inline void br_timer_init(struct timer_list *timer,
-                         void (*_function)(unsigned long),
-                         unsigned long _data)
-{
-       init_timer(timer);
-       timer->function = _function;
-       timer->data = _data;
+       spin_unlock(&p->br->lock);
 }
 
 void br_stp_timer_init(struct net_bridge *br)
 {
-       br_timer_init(&br->hello_timer, br_hello_timer_expired,
+       setup_timer(&br->hello_timer, br_hello_timer_expired,
                      (unsigned long) br);
 
-       br_timer_init(&br->tcn_timer, br_tcn_timer_expired, 
+       setup_timer(&br->tcn_timer, br_tcn_timer_expired,
                      (unsigned long) br);
 
-       br_timer_init(&br->topology_change_timer,
+       setup_timer(&br->topology_change_timer,
                      br_topology_change_timer_expired,
                      (unsigned long) br);
 
-       br_timer_init(&br->gc_timer, br_fdb_cleanup, (unsigned long) br);
+       setup_timer(&br->gc_timer, br_fdb_cleanup, (unsigned long) br);
 }
 
 void br_stp_port_timer_init(struct net_bridge_port *p)
 {
-       br_timer_init(&p->message_age_timer, br_message_age_timer_expired,
+       setup_timer(&p->message_age_timer, br_message_age_timer_expired,
                      (unsigned long) p);
 
-       br_timer_init(&p->forward_delay_timer, br_forward_delay_timer_expired,
+       setup_timer(&p->forward_delay_timer, br_forward_delay_timer_expired,
                      (unsigned long) p);
                      
-       br_timer_init(&p->hold_timer, br_hold_timer_expired,
+       setup_timer(&p->hold_timer, br_hold_timer_expired,
                      (unsigned long) p);
 }      
 
index 6f577f1..96bcb2f 100644 (file)
@@ -242,6 +242,54 @@ static ssize_t show_gc_timer(struct class_device *cd, char *buf)
 }
 static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
 
+static ssize_t show_group_addr(struct class_device *cd, char *buf)
+{
+       struct net_bridge *br = to_bridge(cd);
+       return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
+                      br->group_addr[0], br->group_addr[1],
+                      br->group_addr[2], br->group_addr[3],
+                      br->group_addr[4], br->group_addr[5]);
+}
+
+static ssize_t store_group_addr(struct class_device *cd, const char *buf,
+                                   size_t len)
+{
+       struct net_bridge *br = to_bridge(cd);
+       unsigned new_addr[6];
+       int i;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
+                  &new_addr[0], &new_addr[1], &new_addr[2],
+                  &new_addr[3], &new_addr[4], &new_addr[5]) != 6)
+               return -EINVAL;
+
+       /* Must be 01:80:c2:00:00:0X */
+       for (i = 0; i < 5; i++)
+               if (new_addr[i] != br_group_address[i])
+                       return -EINVAL;
+
+       if (new_addr[5] & ~0xf)
+               return -EINVAL;
+
+       if (new_addr[5] == 1    /* 802.3x Pause address */
+           || new_addr[5] == 2 /* 802.3ad Slow protocols */
+           || new_addr[5] == 3) /* 802.1X PAE address */
+               return -EINVAL;
+
+       spin_lock_bh(&br->lock);
+       for (i = 0; i < 6; i++)
+               br->group_addr[i] = new_addr[i];
+       spin_unlock_bh(&br->lock);
+       return len;
+}
+
+static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
+                        show_group_addr, store_group_addr);
+
+
 static struct attribute *bridge_attrs[] = {
        &class_device_attr_forward_delay.attr,
        &class_device_attr_hello_time.attr,
@@ -259,6 +307,7 @@ static struct attribute *bridge_attrs[] = {
        &class_device_attr_tcn_timer.attr,
        &class_device_attr_topology_change_timer.attr,
        &class_device_attr_gc_timer.attr,
+       &class_device_attr_group_addr.attr,
        NULL
 };
 
index cbd4020..9979533 100644 (file)
@@ -35,6 +35,7 @@
 #define ASSERT_READ_LOCK(x)
 #define ASSERT_WRITE_LOCK(x)
 #include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/mutex.h>
 
 #if 0
 /* use this for remote debugging
@@ -81,7 +82,7 @@ static void print_string(char *str)
 
 
 
-static DECLARE_MUTEX(ebt_mutex);
+static DEFINE_MUTEX(ebt_mutex);
 static LIST_HEAD(ebt_tables);
 static LIST_HEAD(ebt_targets);
 static LIST_HEAD(ebt_matches);
@@ -296,18 +297,18 @@ letscontinue:
 /* If it succeeds, returns element and locks mutex */
 static inline void *
 find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
-   struct semaphore *mutex)
+   struct mutex *mutex)
 {
        void *ret;
 
-       *error = down_interruptible(mutex);
+       *error = mutex_lock_interruptible(mutex);
        if (*error != 0)
                return NULL;
 
        ret = list_named_find(head, name);
        if (!ret) {
                *error = -ENOENT;
-               up(mutex);
+               mutex_unlock(mutex);
        }
        return ret;
 }
@@ -317,7 +318,7 @@ find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
 #else
 static void *
 find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
-   int *error, struct semaphore *mutex)
+   int *error, struct mutex *mutex)
 {
        void *ret;
 
@@ -331,25 +332,25 @@ find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
 #endif
 
 static inline struct ebt_table *
-find_table_lock(const char *name, int *error, struct semaphore *mutex)
+find_table_lock(const char *name, int *error, struct mutex *mutex)
 {
        return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
 }
 
 static inline struct ebt_match *
-find_match_lock(const char *name, int *error, struct semaphore *mutex)
+find_match_lock(const char *name, int *error, struct mutex *mutex)
 {
        return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
 }
 
 static inline struct ebt_watcher *
-find_watcher_lock(const char *name, int *error, struct semaphore *mutex)
+find_watcher_lock(const char *name, int *error, struct mutex *mutex)
 {
        return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
 }
 
 static inline struct ebt_target *
-find_target_lock(const char *name, int *error, struct semaphore *mutex)
+find_target_lock(const char *name, int *error, struct mutex *mutex)
 {
        return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
 }
@@ -369,10 +370,10 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
                return ret;
        m->u.match = match;
        if (!try_module_get(match->me)) {
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                return -ENOENT;
        }
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
        if (match->check &&
           match->check(name, hookmask, e, m->data, m->match_size) != 0) {
                BUGPRINT("match->check failed\n");
@@ -398,10 +399,10 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
                return ret;
        w->u.watcher = watcher;
        if (!try_module_get(watcher->me)) {
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                return -ENOENT;
        }
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
        if (watcher->check &&
           watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
                BUGPRINT("watcher->check failed\n");
@@ -638,11 +639,11 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
        if (!target)
                goto cleanup_watchers;
        if (!try_module_get(target->me)) {
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                ret = -ENOENT;
                goto cleanup_watchers;
        }
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 
        t->u.target = target;
        if (t->u.target == &ebt_standard_target) {
@@ -1015,7 +1016,7 @@ static int do_replace(void __user *user, unsigned int len)
 
        t->private = newinfo;
        write_unlock_bh(&t->lock);
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
        /* so, a user can change the chains while having messed up her counter
           allocation. Only reason why this is done is because this way the lock
           is held only once, while this doesn't bring the kernel into a
@@ -1045,7 +1046,7 @@ static int do_replace(void __user *user, unsigned int len)
        return ret;
 
 free_unlock:
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 free_iterate:
        EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
           ebt_cleanup_entry, NULL);
@@ -1068,69 +1069,69 @@ int ebt_register_target(struct ebt_target *target)
 {
        int ret;
 
-       ret = down_interruptible(&ebt_mutex);
+       ret = mutex_lock_interruptible(&ebt_mutex);
        if (ret != 0)
                return ret;
        if (!list_named_insert(&ebt_targets, target)) {
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                return -EEXIST;
        }
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 
        return 0;
 }
 
 void ebt_unregister_target(struct ebt_target *target)
 {
-       down(&ebt_mutex);
+       mutex_lock(&ebt_mutex);
        LIST_DELETE(&ebt_targets, target);
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_match(struct ebt_match *match)
 {
        int ret;
 
-       ret = down_interruptible(&ebt_mutex);
+       ret = mutex_lock_interruptible(&ebt_mutex);
        if (ret != 0)
                return ret;
        if (!list_named_insert(&ebt_matches, match)) {
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                return -EEXIST;
        }
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 
        return 0;
 }
 
 void ebt_unregister_match(struct ebt_match *match)
 {
-       down(&ebt_mutex);
+       mutex_lock(&ebt_mutex);
        LIST_DELETE(&ebt_matches, match);
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_watcher(struct ebt_watcher *watcher)
 {
        int ret;
 
-       ret = down_interruptible(&ebt_mutex);
+       ret = mutex_lock_interruptible(&ebt_mutex);
        if (ret != 0)
                return ret;
        if (!list_named_insert(&ebt_watchers, watcher)) {
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                return -EEXIST;
        }
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 
        return 0;
 }
 
 void ebt_unregister_watcher(struct ebt_watcher *watcher)
 {
-       down(&ebt_mutex);
+       mutex_lock(&ebt_mutex);
        LIST_DELETE(&ebt_watchers, watcher);
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 }
 
 int ebt_register_table(struct ebt_table *table)
@@ -1178,7 +1179,7 @@ int ebt_register_table(struct ebt_table *table)
 
        table->private = newinfo;
        rwlock_init(&table->lock);
-       ret = down_interruptible(&ebt_mutex);
+       ret = mutex_lock_interruptible(&ebt_mutex);
        if (ret != 0)
                goto free_chainstack;
 
@@ -1194,10 +1195,10 @@ int ebt_register_table(struct ebt_table *table)
                goto free_unlock;
        }
        list_prepend(&ebt_tables, table);
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
        return 0;
 free_unlock:
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 free_chainstack:
        if (newinfo->chainstack) {
                for_each_cpu(i)
@@ -1218,9 +1219,9 @@ void ebt_unregister_table(struct ebt_table *table)
                BUGPRINT("Request to unregister NULL table!!!\n");
                return;
        }
-       down(&ebt_mutex);
+       mutex_lock(&ebt_mutex);
        LIST_DELETE(&ebt_tables, table);
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
        vfree(table->private->entries);
        if (table->private->chainstack) {
                for_each_cpu(i)
@@ -1281,7 +1282,7 @@ static int update_counters(void __user *user, unsigned int len)
        write_unlock_bh(&t->lock);
        ret = 0;
 unlock_mutex:
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
 free_tmp:
        vfree(tmp);
        return ret;
@@ -1328,7 +1329,7 @@ static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase)
        return 0;
 }
 
-/* called with ebt_mutex down */
+/* called with ebt_mutex locked */
 static int copy_everything_to_user(struct ebt_table *t, void __user *user,
    int *len, int cmd)
 {
@@ -1440,7 +1441,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        case EBT_SO_GET_INIT_INFO:
                if (*len != sizeof(struct ebt_replace)){
                        ret = -EINVAL;
-                       up(&ebt_mutex);
+                       mutex_unlock(&ebt_mutex);
                        break;
                }
                if (cmd == EBT_SO_GET_INFO) {
@@ -1452,7 +1453,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
                        tmp.entries_size = t->table->entries_size;
                        tmp.valid_hooks = t->table->valid_hooks;
                }
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                if (copy_to_user(user, &tmp, *len) != 0){
                        BUGPRINT("c2u Didn't work\n");
                        ret = -EFAULT;
@@ -1464,11 +1465,11 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        case EBT_SO_GET_ENTRIES:
        case EBT_SO_GET_INIT_ENTRIES:
                ret = copy_everything_to_user(t, user, len, cmd);
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                break;
 
        default:
-               up(&ebt_mutex);
+               mutex_unlock(&ebt_mutex);
                ret = -EINVAL;
        }
 
@@ -1476,17 +1477,23 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 }
 
 static struct nf_sockopt_ops ebt_sockopts =
-{ { NULL, NULL }, PF_INET, EBT_BASE_CTL, EBT_SO_SET_MAX + 1, do_ebt_set_ctl,
-    EBT_BASE_CTL, EBT_SO_GET_MAX + 1, do_ebt_get_ctl, 0, NULL
+{
+       .pf             = PF_INET,
+       .set_optmin     = EBT_BASE_CTL,
+       .set_optmax     = EBT_SO_SET_MAX + 1,
+       .set            = do_ebt_set_ctl,
+       .get_optmin     = EBT_BASE_CTL,
+       .get_optmax     = EBT_SO_GET_MAX + 1,
+       .get            = do_ebt_get_ctl,
 };
 
 static int __init init(void)
 {
        int ret;
 
-       down(&ebt_mutex);
+       mutex_lock(&ebt_mutex);
        list_named_insert(&ebt_targets, &ebt_standard_target);
-       up(&ebt_mutex);
+       mutex_unlock(&ebt_mutex);
        if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
                return ret;
 
index e593dac..13177a1 100644 (file)
@@ -416,7 +416,7 @@ struct compat_sock_fprog {
        compat_uptr_t   filter;         /* struct sock_filter * */
 };
 
-static int do_set_attach_filter(int fd, int level, int optname,
+static int do_set_attach_filter(struct socket *sock, int level, int optname,
                                char __user *optval, int optlen)
 {
        struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval;
@@ -432,11 +432,12 @@ static int do_set_attach_filter(int fd, int level, int optname,
            __put_user(compat_ptr(ptr), &kfprog->filter))
                return -EFAULT;
 
-       return sys_setsockopt(fd, level, optname, (char __user *)kfprog, 
+       return sock_setsockopt(sock, level, optname, (char __user *)kfprog,
                              sizeof(struct sock_fprog));
 }
 
-static int do_set_sock_timeout(int fd, int level, int optname, char __user *optval, int optlen)
+static int do_set_sock_timeout(struct socket *sock, int level,
+               int optname, char __user *optval, int optlen)
 {
        struct compat_timeval __user *up = (struct compat_timeval __user *) optval;
        struct timeval ktime;
@@ -451,30 +452,61 @@ static int do_set_sock_timeout(int fd, int level, int optname, char __user *optv
                return -EFAULT;
        old_fs = get_fs();
        set_fs(KERNEL_DS);
-       err = sys_setsockopt(fd, level, optname, (char *) &ktime, sizeof(ktime));
+       err = sock_setsockopt(sock, level, optname, (char *) &ktime, sizeof(ktime));
        set_fs(old_fs);
 
        return err;
 }
 
+static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
+                               char __user *optval, int optlen)
+{
+       if (optname == SO_ATTACH_FILTER)
+               return do_set_attach_filter(sock, level, optname,
+                                           optval, optlen);
+       if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+               return do_set_sock_timeout(sock, level, optname, optval, optlen);
+
+       return sock_setsockopt(sock, level, optname, optval, optlen);
+}
+
 asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
                                char __user *optval, int optlen)
 {
+       int err;
+       struct socket *sock;
+
        /* SO_SET_REPLACE seems to be the same in all levels */
        if (optname == IPT_SO_SET_REPLACE)
                return do_netfilter_replace(fd, level, optname,
                                            optval, optlen);
-       if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER)
-               return do_set_attach_filter(fd, level, optname,
-                                           optval, optlen);
-       if (level == SOL_SOCKET &&
-           (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
-               return do_set_sock_timeout(fd, level, optname, optval, optlen);
 
-       return sys_setsockopt(fd, level, optname, optval, optlen);
+       if (optlen < 0)
+               return -EINVAL;
+
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               err = security_socket_setsockopt(sock,level,optname);
+               if (err) {
+                       sockfd_put(sock);
+                       return err;
+               }
+
+               if (level == SOL_SOCKET)
+                       err = compat_sock_setsockopt(sock, level,
+                                       optname, optval, optlen);
+               else if (sock->ops->compat_setsockopt)
+                       err = sock->ops->compat_setsockopt(sock, level,
+                                       optname, optval, optlen);
+               else
+                       err = sock->ops->setsockopt(sock, level,
+                                       optname, optval, optlen);
+               sockfd_put(sock);
+       }
+       return err;
 }
 
-static int do_get_sock_timeout(int fd, int level, int optname,
+static int do_get_sock_timeout(struct socket *sock, int level, int optname,
                char __user *optval, int __user *optlen)
 {
        struct compat_timeval __user *up;
@@ -490,7 +522,7 @@ static int do_get_sock_timeout(int fd, int level, int optname,
        len = sizeof(ktime);
        old_fs = get_fs();
        set_fs(KERNEL_DS);
-       err = sys_getsockopt(fd, level, optname, (char *) &ktime, &len);
+       err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len);
        set_fs(old_fs);
 
        if (!err) {
@@ -503,15 +535,42 @@ static int do_get_sock_timeout(int fd, int level, int optname,
        return err;
 }
 
-asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
+static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
                                char __user *optval, int __user *optlen)
 {
-       if (level == SOL_SOCKET &&
-           (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
-               return do_get_sock_timeout(fd, level, optname, optval, optlen);
-       return sys_getsockopt(fd, level, optname, optval, optlen);
+       if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+               return do_get_sock_timeout(sock, level, optname, optval, optlen);
+       return sock_getsockopt(sock, level, optname, optval, optlen);
 }
 
+asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
+                               char __user *optval, int __user *optlen)
+{
+       int err;
+       struct socket *sock;
+
+       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       {
+               err = security_socket_getsockopt(sock, level,
+                                                          optname);
+               if (err) {
+                       sockfd_put(sock);
+                       return err;
+               }
+
+               if (level == SOL_SOCKET)
+                       err = compat_sock_getsockopt(sock, level,
+                                       optname, optval, optlen);
+               else if (sock->ops->compat_getsockopt)
+                       err = sock->ops->compat_getsockopt(sock, level,
+                                       optname, optval, optlen);
+               else
+                       err = sock->ops->getsockopt(sock, level,
+                                       optname, optval, optlen);
+               sockfd_put(sock);
+       }
+       return err;
+}
 /* Argument list sizes for compat_sys_socketcall */
 #define AL(x) ((x) * sizeof(u32))
 static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
index ef56c03..08dec6e 100644 (file)
@@ -81,6 +81,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/socket.h>
@@ -1759,8 +1760,7 @@ static void net_rx_action(struct softirq_action *h)
                if (dev->quota <= 0 || dev->poll(dev, &budget)) {
                        netpoll_poll_unlock(have);
                        local_irq_disable();
-                       list_del(&dev->poll_list);
-                       list_add_tail(&dev->poll_list, &queue->poll_list);
+                       list_move_tail(&dev->poll_list, &queue->poll_list);
                        if (dev->quota < 0)
                                dev->quota += dev->weight;
                        else
@@ -2174,12 +2174,20 @@ unsigned dev_get_flags(const struct net_device *dev)
 
        flags = (dev->flags & ~(IFF_PROMISC |
                                IFF_ALLMULTI |
-                               IFF_RUNNING)) | 
+                               IFF_RUNNING |
+                               IFF_LOWER_UP |
+                               IFF_DORMANT)) |
                (dev->gflags & (IFF_PROMISC |
                                IFF_ALLMULTI));
 
-       if (netif_running(dev) && netif_carrier_ok(dev))
-               flags |= IFF_RUNNING;
+       if (netif_running(dev)) {
+               if (netif_oper_up(dev))
+                       flags |= IFF_RUNNING;
+               if (netif_carrier_ok(dev))
+                       flags |= IFF_LOWER_UP;
+               if (netif_dormant(dev))
+                       flags |= IFF_DORMANT;
+       }
 
        return flags;
 }
@@ -2458,9 +2466,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
         */
 
        if (cmd == SIOCGIFCONF) {
-               rtnl_shlock();
+               rtnl_lock();
                ret = dev_ifconf((char __user *) arg);
-               rtnl_shunlock();
+               rtnl_unlock();
                return ret;
        }
        if (cmd == SIOCGIFNAME)
@@ -2869,7 +2877,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
        rebroadcast_time = warning_time = jiffies;
        while (atomic_read(&dev->refcnt) != 0) {
                if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
-                       rtnl_shlock();
+                       rtnl_lock();
 
                        /* Rebroadcast unregister notification */
                        notifier_call_chain(&netdev_chain,
@@ -2886,7 +2894,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
                                linkwatch_run_queue();
                        }
 
-                       rtnl_shunlock();
+                       __rtnl_unlock();
 
                        rebroadcast_time = jiffies;
                }
@@ -2924,7 +2932,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
  * 2) Since we run with the RTNL semaphore not held, we can sleep
  *    safely in order to wait for the netdev refcnt to drop to zero.
  */
-static DECLARE_MUTEX(net_todo_run_mutex);
+static DEFINE_MUTEX(net_todo_run_mutex);
 void netdev_run_todo(void)
 {
        struct list_head list = LIST_HEAD_INIT(list);
@@ -2932,7 +2940,7 @@ void netdev_run_todo(void)
 
 
        /* Need to guard against multiple cpu's getting out of order. */
-       down(&net_todo_run_mutex);
+       mutex_lock(&net_todo_run_mutex);
 
        /* Not safe to do outside the semaphore.  We must not return
         * until all unregister events invoked by the local processor
@@ -2989,7 +2997,7 @@ void netdev_run_todo(void)
        }
 
 out:
-       up(&net_todo_run_mutex);
+       mutex_unlock(&net_todo_run_mutex);
 }
 
 /**
index c4f2538..55789f8 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
+#include <linux/mutex.h>
 #include <net/flow.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
@@ -287,11 +288,11 @@ static void flow_cache_flush_per_cpu(void *data)
 void flow_cache_flush(void)
 {
        struct flow_flush_info info;
-       static DECLARE_MUTEX(flow_flush_sem);
+       static DEFINE_MUTEX(flow_flush_sem);
 
        /* Don't want cpus going down or up during this. */
        lock_cpu_hotplug();
-       down(&flow_flush_sem);
+       mutex_lock(&flow_flush_sem);
        atomic_set(&info.cpuleft, num_online_cpus());
        init_completion(&info.completion);
 
@@ -301,7 +302,7 @@ void flow_cache_flush(void)
        local_bh_enable();
 
        wait_for_completion(&info.completion);
-       up(&flow_flush_sem);
+       mutex_unlock(&flow_flush_sem);
        unlock_cpu_hotplug();
 }
 
index d43d120..341de44 100644 (file)
@@ -49,6 +49,45 @@ struct lw_event {
 /* Avoid kmalloc() for most systems */
 static struct lw_event singleevent;
 
+static unsigned char default_operstate(const struct net_device *dev)
+{
+       if (!netif_carrier_ok(dev))
+               return (dev->ifindex != dev->iflink ?
+                       IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN);
+
+       if (netif_dormant(dev))
+               return IF_OPER_DORMANT;
+
+       return IF_OPER_UP;
+}
+
+
+static void rfc2863_policy(struct net_device *dev)
+{
+       unsigned char operstate = default_operstate(dev);
+
+       if (operstate == dev->operstate)
+               return;
+
+       write_lock_bh(&dev_base_lock);
+
+       switch(dev->link_mode) {
+       case IF_LINK_MODE_DORMANT:
+               if (operstate == IF_OPER_UP)
+                       operstate = IF_OPER_DORMANT;
+               break;
+
+       case IF_LINK_MODE_DEFAULT:
+       default:
+               break;
+       };
+
+       dev->operstate = operstate;
+
+       write_unlock_bh(&dev_base_lock);
+}
+
+
 /* Must be called with the rtnl semaphore held */
 void linkwatch_run_queue(void)
 {
@@ -74,6 +113,7 @@ void linkwatch_run_queue(void)
                 */
                clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
 
+               rfc2863_policy(dev);
                if (dev->flags & IFF_UP) {
                        if (netif_carrier_ok(dev)) {
                                WARN_ON(dev->qdisc_sleeping == &noop_qdisc);
@@ -99,9 +139,9 @@ static void linkwatch_event(void *dummy)
        linkwatch_nextevent = jiffies + HZ;
        clear_bit(LW_RUNNING, &linkwatch_flags);
 
-       rtnl_shlock();
+       rtnl_lock();
        linkwatch_run_queue();
-       rtnl_shunlock();
+       rtnl_unlock();
 }
 
 
index e68700f..0c86668 100644 (file)
@@ -586,8 +586,8 @@ void neigh_destroy(struct neighbour *neigh)
                        kfree(hh);
        }
 
-       if (neigh->ops && neigh->ops->destructor)
-               (neigh->ops->destructor)(neigh);
+       if (neigh->parms->neigh_destructor)
+               (neigh->parms->neigh_destructor)(neigh);
 
        skb_queue_purge(&neigh->arp_queue);
 
@@ -750,11 +750,13 @@ static void neigh_timer_handler(unsigned long arg)
                                          neigh->used + neigh->parms->delay_probe_time)) {
                        NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
                        neigh->nud_state = NUD_DELAY;
+                       neigh->updated = jiffies;
                        neigh_suspect(neigh);
                        next = now + neigh->parms->delay_probe_time;
                } else {
                        NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
                        neigh->nud_state = NUD_STALE;
+                       neigh->updated = jiffies;
                        neigh_suspect(neigh);
                }
        } else if (state & NUD_DELAY) {
@@ -762,11 +764,13 @@ static void neigh_timer_handler(unsigned long arg)
                                   neigh->confirmed + neigh->parms->delay_probe_time)) {
                        NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
                        neigh->nud_state = NUD_REACHABLE;
+                       neigh->updated = jiffies;
                        neigh_connect(neigh);
                        next = neigh->confirmed + neigh->parms->reachable_time;
                } else {
                        NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
                        neigh->nud_state = NUD_PROBE;
+                       neigh->updated = jiffies;
                        atomic_set(&neigh->probes, 0);
                        next = now + neigh->parms->retrans_time;
                }
@@ -780,6 +784,7 @@ static void neigh_timer_handler(unsigned long arg)
                struct sk_buff *skb;
 
                neigh->nud_state = NUD_FAILED;
+               neigh->updated = jiffies;
                notify = 1;
                NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
                NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
@@ -843,10 +848,12 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
                        atomic_set(&neigh->probes, neigh->parms->ucast_probes);
                        neigh->nud_state     = NUD_INCOMPLETE;
+                       neigh->updated = jiffies;
                        neigh_hold(neigh);
                        neigh_add_timer(neigh, now + 1);
                } else {
                        neigh->nud_state = NUD_FAILED;
+                       neigh->updated = jiffies;
                        write_unlock_bh(&neigh->lock);
 
                        if (skb)
@@ -857,6 +864,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
                neigh_hold(neigh);
                neigh->nud_state = NUD_DELAY;
+               neigh->updated = jiffies;
                neigh_add_timer(neigh,
                                jiffies + neigh->parms->delay_probe_time);
        }
index e8b2acb..21b6846 100644 (file)
@@ -91,6 +91,7 @@ NETDEVICE_SHOW(iflink, fmt_dec);
 NETDEVICE_SHOW(ifindex, fmt_dec);
 NETDEVICE_SHOW(features, fmt_long_hex);
 NETDEVICE_SHOW(type, fmt_dec);
+NETDEVICE_SHOW(link_mode, fmt_dec);
 
 /* use same locking rules as GIFHWADDR ioctl's */
 static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
@@ -133,6 +134,43 @@ static ssize_t show_carrier(struct class_device *dev, char *buf)
        return -EINVAL;
 }
 
+static ssize_t show_dormant(struct class_device *dev, char *buf)
+{
+       struct net_device *netdev = to_net_dev(dev);
+
+       if (netif_running(netdev))
+               return sprintf(buf, fmt_dec, !!netif_dormant(netdev));
+
+       return -EINVAL;
+}
+
+static const char *operstates[] = {
+       "unknown",
+       "notpresent", /* currently unused */
+       "down",
+       "lowerlayerdown",
+       "testing", /* currently unused */
+       "dormant",
+       "up"
+};
+
+static ssize_t show_operstate(struct class_device *dev, char *buf)
+{
+       const struct net_device *netdev = to_net_dev(dev);
+       unsigned char operstate;
+
+       read_lock(&dev_base_lock);
+       operstate = netdev->operstate;
+       if (!netif_running(netdev))
+               operstate = IF_OPER_DOWN;
+       read_unlock(&dev_base_lock);
+
+       if (operstate >= sizeof(operstates))
+               return -EINVAL; /* should not happen */
+
+       return sprintf(buf, "%s\n", operstates[operstate]);
+}
+
 /* read-write attributes */
 NETDEVICE_SHOW(mtu, fmt_dec);
 
@@ -190,9 +228,12 @@ static struct class_device_attribute net_class_attributes[] = {
        __ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
        __ATTR(features, S_IRUGO, show_features, NULL),
        __ATTR(type, S_IRUGO, show_type, NULL),
+       __ATTR(link_mode, S_IRUGO, show_link_mode, NULL),
        __ATTR(address, S_IRUGO, show_address, NULL),
        __ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
        __ATTR(carrier, S_IRUGO, show_carrier, NULL),
+       __ATTR(dormant, S_IRUGO, show_dormant, NULL),
+       __ATTR(operstate, S_IRUGO, show_operstate, NULL),
        __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu),
        __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags),
        __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len,
index ea51f8d..e8e05ce 100644 (file)
@@ -669,14 +669,14 @@ int netpoll_setup(struct netpoll *np)
                printk(KERN_INFO "%s: device %s not up yet, forcing it\n",
                       np->name, np->dev_name);
 
-               rtnl_shlock();
+               rtnl_lock();
                if (dev_change_flags(ndev, ndev->flags | IFF_UP) < 0) {
                        printk(KERN_ERR "%s: failed to open %s\n",
                               np->name, np->dev_name);
-                       rtnl_shunlock();
+                       rtnl_unlock();
                        goto release;
                }
-               rtnl_shunlock();
+               rtnl_unlock();
 
                atleast = jiffies + HZ/10;
                atmost = jiffies + 4*HZ;
index da16f8f..8eedaed 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/capability.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
+#include <linux/list.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
-#include <asm/div64.h> /* do_div */
+#include <asm/div64.h>         /* do_div */
 #include <asm/timex.h>
 
-
-#define VERSION  "pktgen v2.63: Packet Generator for packet performance testing.\n"
+#define VERSION  "pktgen v2.66: Packet Generator for packet performance testing.\n"
 
 /* #define PG_DEBUG(a) a */
-#define PG_DEBUG(a) 
+#define PG_DEBUG(a)
 
 /* The buckets are exponential in 'width' */
 #define LAT_BUCKETS_MAX 32
 #define IP_NAME_SZ 32
 
 /* Device flag bits */
-#define F_IPSRC_RND   (1<<0)  /* IP-Src Random  */
-#define F_IPDST_RND   (1<<1)  /* IP-Dst Random  */
-#define F_UDPSRC_RND  (1<<2)  /* UDP-Src Random */
-#define F_UDPDST_RND  (1<<3)  /* UDP-Dst Random */
-#define F_MACSRC_RND  (1<<4)  /* MAC-Src Random */
-#define F_MACDST_RND  (1<<5)  /* MAC-Dst Random */
-#define F_TXSIZE_RND  (1<<6)  /* Transmit size is random */
-#define F_IPV6        (1<<7)  /* Interface in IPV6 Mode */
+#define F_IPSRC_RND   (1<<0)   /* IP-Src Random  */
+#define F_IPDST_RND   (1<<1)   /* IP-Dst Random  */
+#define F_UDPSRC_RND  (1<<2)   /* UDP-Src Random */
+#define F_UDPDST_RND  (1<<3)   /* UDP-Dst Random */
+#define F_MACSRC_RND  (1<<4)   /* MAC-Src Random */
+#define F_MACDST_RND  (1<<5)   /* MAC-Dst Random */
+#define F_TXSIZE_RND  (1<<6)   /* Transmit size is random */
+#define F_IPV6        (1<<7)   /* Interface in IPV6 Mode */
 
 /* Thread control flag bits */
-#define T_TERMINATE   (1<<0)  
-#define T_STOP        (1<<1)  /* Stop run */
-#define T_RUN         (1<<2)  /* Start run */
-#define T_REMDEV      (1<<3)  /* Remove all devs */
-
-/* Locks */
-#define   thread_lock()        down(&pktgen_sem)
-#define   thread_unlock()      up(&pktgen_sem)
+#define T_TERMINATE   (1<<0)
+#define T_STOP        (1<<1)   /* Stop run */
+#define T_RUN         (1<<2)   /* Start run */
+#define T_REMDEVALL   (1<<3)   /* Remove all devs */
+#define T_REMDEV      (1<<4)   /* Remove one dev */
 
 /* If lock -- can be removed after some work */
 #define   if_lock(t)           spin_lock(&(t->if_lock));
@@ -194,10 +192,9 @@ static struct proc_dir_entry *pg_proc_dir = NULL;
 
 #define MAX_CFLOWS  65536
 
-struct flow_state
-{
-       __u32           cur_daddr;
-       int             count;
+struct flow_state {
+       __u32 cur_daddr;
+       int count;
 };
 
 struct pktgen_dev {
@@ -206,141 +203,144 @@ struct pktgen_dev {
         * Try to keep frequent/infrequent used vars. separated.
         */
 
-        char ifname[IFNAMSIZ];
-        char result[512];
-
-        struct pktgen_thread* pg_thread; /* the owner */
-        struct pktgen_dev *next; /* Used for chaining in the thread's run-queue */
-
-        int running;  /* if this changes to false, the test will stop */
-        
-        /* If min != max, then we will either do a linear iteration, or
-         * we will do a random selection from within the range.
-         */
-        __u32 flags;     
-
-        int min_pkt_size;    /* = ETH_ZLEN; */
-        int max_pkt_size;    /* = ETH_ZLEN; */
-        int nfrags;
-        __u32 delay_us;    /* Default delay */
-        __u32 delay_ns;
-        __u64 count;  /* Default No packets to send */
-        __u64 sofar;  /* How many pkts we've sent so far */
-        __u64 tx_bytes; /* How many bytes we've transmitted */
-        __u64 errors;    /* Errors when trying to transmit, pkts will be re-sent */
-
-        /* runtime counters relating to clone_skb */
-        __u64 next_tx_us;          /* timestamp of when to tx next */
-        __u32 next_tx_ns;
-        
-        __u64 allocated_skbs;
-        __u32 clone_count;
-       int last_ok;           /* Was last skb sent? 
-                               * Or a failed transmit of some sort?  This will keep
-                                * sequence numbers in order, for example.
-                               */
-        __u64 started_at; /* micro-seconds */
-        __u64 stopped_at; /* micro-seconds */
-        __u64 idle_acc; /* micro-seconds */
-        __u32 seq_num;
-        
-        int clone_skb; /* Use multiple SKBs during packet gen.  If this number
-                          * is greater than 1, then that many copies of the same
-                          * packet will be sent before a new packet is allocated.
-                          * For instance, if you want to send 1024 identical packets
-                          * before creating a new packet, set clone_skb to 1024.
-                          */
-        
-        char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */
-        char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */
-        char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */
-        char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */
-
-       struct in6_addr  in6_saddr;
-       struct in6_addr  in6_daddr;
-       struct in6_addr  cur_in6_daddr;
-       struct in6_addr  cur_in6_saddr;
+       char ifname[IFNAMSIZ];
+       char result[512];
+
+       struct pktgen_thread *pg_thread;        /* the owner */
+       struct list_head list;          /* Used for chaining in the thread's run-queue */
+
+       int running;            /* if this changes to false, the test will stop */
+
+       /* If min != max, then we will either do a linear iteration, or
+        * we will do a random selection from within the range.
+        */
+       __u32 flags;
+       int removal_mark;       /* non-zero => the device is marked for
+                                * removal by worker thread */
+
+       int min_pkt_size;       /* = ETH_ZLEN; */
+       int max_pkt_size;       /* = ETH_ZLEN; */
+       int nfrags;
+       __u32 delay_us;         /* Default delay */
+       __u32 delay_ns;
+       __u64 count;            /* Default No packets to send */
+       __u64 sofar;            /* How many pkts we've sent so far */
+       __u64 tx_bytes;         /* How many bytes we've transmitted */
+       __u64 errors;           /* Errors when trying to transmit, pkts will be re-sent */
+
+       /* runtime counters relating to clone_skb */
+       __u64 next_tx_us;       /* timestamp of when to tx next */
+       __u32 next_tx_ns;
+
+       __u64 allocated_skbs;
+       __u32 clone_count;
+       int last_ok;            /* Was last skb sent?
+                                * Or a failed transmit of some sort?  This will keep
+                                * sequence numbers in order, for example.
+                                */
+       __u64 started_at;       /* micro-seconds */
+       __u64 stopped_at;       /* micro-seconds */
+       __u64 idle_acc;         /* micro-seconds */
+       __u32 seq_num;
+
+       int clone_skb;          /* Use multiple SKBs during packet gen.  If this number
+                                * is greater than 1, then that many copies of the same
+                                * packet will be sent before a new packet is allocated.
+                                * For instance, if you want to send 1024 identical packets
+                                * before creating a new packet, set clone_skb to 1024.
+                                */
+
+       char dst_min[IP_NAME_SZ];       /* IP, ie 1.2.3.4 */
+       char dst_max[IP_NAME_SZ];       /* IP, ie 1.2.3.4 */
+       char src_min[IP_NAME_SZ];       /* IP, ie 1.2.3.4 */
+       char src_max[IP_NAME_SZ];       /* IP, ie 1.2.3.4 */
+
+       struct in6_addr in6_saddr;
+       struct in6_addr in6_daddr;
+       struct in6_addr cur_in6_daddr;
+       struct in6_addr cur_in6_saddr;
        /* For ranges */
-       struct in6_addr  min_in6_daddr;
-       struct in6_addr  max_in6_daddr;
-       struct in6_addr  min_in6_saddr;
-       struct in6_addr  max_in6_saddr;
-
-        /* If we're doing ranges, random or incremental, then this
-         * defines the min/max for those ranges.
-         */
-        __u32 saddr_min; /* inclusive, source IP address */
-        __u32 saddr_max; /* exclusive, source IP address */
-        __u32 daddr_min; /* inclusive, dest IP address */
-        __u32 daddr_max; /* exclusive, dest IP address */
-
-        __u16 udp_src_min; /* inclusive, source UDP port */
-        __u16 udp_src_max; /* exclusive, source UDP port */
-        __u16 udp_dst_min; /* inclusive, dest UDP port */
-        __u16 udp_dst_max; /* exclusive, dest UDP port */
-
-        __u32 src_mac_count; /* How many MACs to iterate through */
-        __u32 dst_mac_count; /* How many MACs to iterate through */
-        
-        unsigned char dst_mac[ETH_ALEN];
-        unsigned char src_mac[ETH_ALEN];
-        
-        __u32 cur_dst_mac_offset;
-        __u32 cur_src_mac_offset;
-        __u32 cur_saddr;
-        __u32 cur_daddr;
-        __u16 cur_udp_dst;
-        __u16 cur_udp_src;
-        __u32 cur_pkt_size;
-        
-        __u8 hh[14];
-        /* = { 
-           0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 
-           
-           We fill in SRC address later
-           0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-           0x08, 0x00
-           };
-        */
-        __u16 pad; /* pad out the hh struct to an even 16 bytes */
-
-        struct sk_buff* skb; /* skb we are to transmit next, mainly used for when we
-                              * are transmitting the same one multiple times
-                              */
-        struct net_device* odev; /* The out-going device.  Note that the device should
-                                  * have it's pg_info pointer pointing back to this
-                                  * device.  This will be set when the user specifies
-                                  * the out-going device name (not when the inject is
-                                  * started as it used to do.)
-                                  */
+       struct in6_addr min_in6_daddr;
+       struct in6_addr max_in6_daddr;
+       struct in6_addr min_in6_saddr;
+       struct in6_addr max_in6_saddr;
+
+       /* If we're doing ranges, random or incremental, then this
+        * defines the min/max for those ranges.
+        */
+       __u32 saddr_min;        /* inclusive, source IP address */
+       __u32 saddr_max;        /* exclusive, source IP address */
+       __u32 daddr_min;        /* inclusive, dest IP address */
+       __u32 daddr_max;        /* exclusive, dest IP address */
+
+       __u16 udp_src_min;      /* inclusive, source UDP port */
+       __u16 udp_src_max;      /* exclusive, source UDP port */
+       __u16 udp_dst_min;      /* inclusive, dest UDP port */
+       __u16 udp_dst_max;      /* exclusive, dest UDP port */
+
+       __u32 src_mac_count;    /* How many MACs to iterate through */
+       __u32 dst_mac_count;    /* How many MACs to iterate through */
+
+       unsigned char dst_mac[ETH_ALEN];
+       unsigned char src_mac[ETH_ALEN];
+
+       __u32 cur_dst_mac_offset;
+       __u32 cur_src_mac_offset;
+       __u32 cur_saddr;
+       __u32 cur_daddr;
+       __u16 cur_udp_dst;
+       __u16 cur_udp_src;
+       __u32 cur_pkt_size;
+
+       __u8 hh[14];
+       /* = {
+          0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
+
+          We fill in SRC address later
+          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+          0x08, 0x00
+          };
+        */
+       __u16 pad;              /* pad out the hh struct to an even 16 bytes */
+
+       struct sk_buff *skb;    /* skb we are to transmit next, mainly used for when we
+                                * are transmitting the same one multiple times
+                                */
+       struct net_device *odev;        /* The out-going device.  Note that the device should
+                                        * have it's pg_info pointer pointing back to this
+                                        * device.  This will be set when the user specifies
+                                        * the out-going device name (not when the inject is
+                                        * started as it used to do.)
+                                        */
        struct flow_state *flows;
-       unsigned cflows;         /* Concurrent flows (config) */
-       unsigned lflow;          /* Flow length  (config) */
-       unsigned nflows;         /* accumulated flows (stats) */
+       unsigned cflows;        /* Concurrent flows (config) */
+       unsigned lflow;         /* Flow length  (config) */
+       unsigned nflows;        /* accumulated flows (stats) */
 };
 
 struct pktgen_hdr {
-        __u32 pgh_magic;
-        __u32 seq_num;
+       __u32 pgh_magic;
+       __u32 seq_num;
        __u32 tv_sec;
        __u32 tv_usec;
 };
 
 struct pktgen_thread {
-        spinlock_t if_lock;
-        struct pktgen_dev *if_list;           /* All device here */
-        struct pktgen_thread* next;
-        char name[32];
-        char result[512];
-        u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
-        
-       /* Field for thread to receive "posted" events terminate, stop ifs etc.*/
-
-        u32 control;
+       spinlock_t if_lock;
+       struct list_head if_list;       /* All device here */
+       struct list_head th_list;
+       int removed;
+       char name[32];
+       char result[512];
+       u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
+
+       /* Field for thread to receive "posted" events terminate, stop ifs etc. */
+
+       u32 control;
        int pid;
        int cpu;
 
-        wait_queue_head_t queue;
+       wait_queue_head_t queue;
 };
 
 #define REMOVE 1
@@ -364,77 +364,76 @@ struct pktgen_thread {
  */
 static inline s64 divremdi3(s64 x, s64 y, int type)
 {
-        u64 a = (x < 0) ? -x : x;
-        u64 b = (y < 0) ? -y : y;
-        u64 res = 0, d = 1;
-
-        if (b > 0) {
-                while (b < a) {
-                        b <<= 1;
-                        d <<= 1;
-                }
-        }
-        
-        do {
-                if ( a >= b ) {
-                        a -= b;
-                        res += d;
-                }
-                b >>= 1;
-                d >>= 1;
-        }
-        while (d);
-
-        if (PG_DIV == type) {
-                return (((x ^ y) & (1ll<<63)) == 0) ? res : -(s64)res;
-        }
-        else {
-                return ((x & (1ll<<63)) == 0) ? a : -(s64)a;
-        }
+       u64 a = (x < 0) ? -x : x;
+       u64 b = (y < 0) ? -y : y;
+       u64 res = 0, d = 1;
+
+       if (b > 0) {
+               while (b < a) {
+                       b <<= 1;
+                       d <<= 1;
+               }
+       }
+
+       do {
+               if (a >= b) {
+                       a -= b;
+                       res += d;
+               }
+               b >>= 1;
+               d >>= 1;
+       }
+       while (d);
+
+       if (PG_DIV == type) {
+               return (((x ^ y) & (1ll << 63)) == 0) ? res : -(s64) res;
+       } else {
+               return ((x & (1ll << 63)) == 0) ? a : -(s64) a;
+       }
 }
 
 /* End of hacks to deal with 64-bit math on x86 */
 
 /** Convert to milliseconds */
-static inline __u64 tv_to_ms(const struct timeval* tv) 
+static inline __u64 tv_to_ms(const struct timeval *tv)
 {
-        __u64 ms = tv->tv_usec / 1000;
-        ms += (__u64)tv->tv_sec * (__u64)1000;
-        return ms;
+       __u64 ms = tv->tv_usec / 1000;
+       ms += (__u64) tv->tv_sec * (__u64) 1000;
+       return ms;
 }
 
-
 /** Convert to micro-seconds */
-static inline __u64 tv_to_us(const struct timeval* tv) 
+static inline __u64 tv_to_us(const struct timeval *tv)
 {
-        __u64 us = tv->tv_usec;
-        us += (__u64)tv->tv_sec * (__u64)1000000;
-        return us;
+       __u64 us = tv->tv_usec;
+       us += (__u64) tv->tv_sec * (__u64) 1000000;
+       return us;
 }
 
-static inline __u64 pg_div(__u64 n, __u32 base) {
-        __u64 tmp = n;
-        do_div(tmp, base);
-        /* printk("pktgen: pg_div, n: %llu  base: %d  rv: %llu\n",
-                  n, base, tmp); */
-        return tmp;
+static inline __u64 pg_div(__u64 n, __u32 base)
+{
+       __u64 tmp = n;
+       do_div(tmp, base);
+       /* printk("pktgen: pg_div, n: %llu  base: %d  rv: %llu\n",
+          n, base, tmp); */
+       return tmp;
 }
 
-static inline __u64 pg_div64(__u64 n, __u64 base) 
+static inline __u64 pg_div64(__u64 n, __u64 base)
 {
-        __u64 tmp = n;
+       __u64 tmp = n;
 /*
  * How do we know if the architecture we are running on
  * supports division with 64 bit base?
  * 
  */
-#if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__) 
+#if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__)
 
-               do_div(tmp, base);
+       do_div(tmp, base);
 #else
-               tmp = divremdi3(n, base, PG_DIV);
+       tmp = divremdi3(n, base, PG_DIV);
 #endif
-        return tmp;
+       return tmp;
 }
 
 static inline u32 pktgen_random(void)
@@ -448,51 +447,51 @@ static inline u32 pktgen_random(void)
 #endif
 }
 
-static inline __u64 getCurMs(void) 
+static inline __u64 getCurMs(void)
 {
-        struct timeval tv;
-        do_gettimeofday(&tv);
-        return tv_to_ms(&tv);
+       struct timeval tv;
+       do_gettimeofday(&tv);
+       return tv_to_ms(&tv);
 }
 
-static inline __u64 getCurUs(void) 
+static inline __u64 getCurUs(void)
 {
-        struct timeval tv;
-        do_gettimeofday(&tv);
-        return tv_to_us(&tv);
+       struct timeval tv;
+       do_gettimeofday(&tv);
+       return tv_to_us(&tv);
 }
 
-static inline __u64 tv_diff(const struct timeval* a, const struct timeval* b) 
+static inline __u64 tv_diff(const struct timeval *a, const struct timeval *b)
 {
-        return tv_to_us(a) - tv_to_us(b);
+       return tv_to_us(a) - tv_to_us(b);
 }
 
-
 /* old include end */
 
 static char version[] __initdata = VERSION;
 
-static int pktgen_remove_device(struct pktgen_thread* t, struct pktgen_dev *i);
-static int pktgen_add_device(struct pktgen_thread* t, const char* ifname);
-static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread* t, const char* ifname);
+static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
+static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
+static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
+                                         const char *ifname);
 static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
 static void pktgen_run_all_threads(void);
 static void pktgen_stop_all_threads_ifs(void);
 static int pktgen_stop_device(struct pktgen_dev *pkt_dev);
-static void pktgen_stop(struct pktgen_threadt);
+static void pktgen_stop(struct pktgen_thread *t);
 static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
-static struct pktgen_dev *pktgen_NN_threads(const char* dev_name, int remove);
-static unsigned int scan_ip6(const char *s,char ip[16]);
-static unsigned int fmt_ip6(char *s,const char ip[16]);
+static int pktgen_mark_device(const char *ifname);
+static unsigned int scan_ip6(const char *s, char ip[16]);
+static unsigned int fmt_ip6(char *s, const char ip[16]);
 
 /* Module parameters, defaults. */
-static int pg_count_d = 1000; /* 1000 pkts by default */
+static int pg_count_d = 1000;  /* 1000 pkts by default */
 static int pg_delay_d;
 static int pg_clone_skb_d;
 static int debug;
 
-static DECLARE_MUTEX(pktgen_sem);
-static struct pktgen_thread *pktgen_threads = NULL;
+static DEFINE_MUTEX(pktgen_thread_lock);
+static LIST_HEAD(pktgen_threads);
 
 static struct notifier_block pktgen_notifier_block = {
        .notifier_call = pktgen_device_event,
@@ -504,21 +503,21 @@ static struct notifier_block pktgen_notifier_block = {
  */
 
 static int pgctrl_show(struct seq_file *seq, void *v)
-{ 
+{
        seq_puts(seq, VERSION);
        return 0;
 }
 
-static ssize_t pgctrl_write(struct file* file,const char __user * buf,
-                           size_t count, loff_t *ppos)
+static ssize_t pgctrl_write(struct file *file, const char __user * buf,
+                           size_t count, loff_t * ppos)
 {
        int err = 0;
        char data[128];
 
-        if (!capable(CAP_NET_ADMIN)){
-                err = -EPERM;
+       if (!capable(CAP_NET_ADMIN)) {
+               err = -EPERM;
                goto out;
-        }
+       }
 
        if (count > sizeof(data))
                count = sizeof(data);
@@ -526,22 +525,22 @@ static ssize_t pgctrl_write(struct file* file,const char __user * buf,
        if (copy_from_user(data, buf, count)) {
                err = -EFAULT;
                goto out;
-       }  
-       data[count-1] = 0; /* Make string */
+       }
+       data[count - 1] = 0;    /* Make string */
 
-       if (!strcmp(data, "stop")) 
+       if (!strcmp(data, "stop"))
                pktgen_stop_all_threads_ifs();
 
-        else if (!strcmp(data, "start")) 
+       else if (!strcmp(data, "start"))
                pktgen_run_all_threads();
 
-       else 
+       else
                printk("pktgen: Unknown command: %s\n", data);
 
        err = count;
 
- out:
-        return err;
+out:
+       return err;
 }
 
 static int pgctrl_open(struct inode *inode, struct file *file)
@@ -550,147 +549,158 @@ static int pgctrl_open(struct inode *inode, struct file *file)
 }
 
 static struct file_operations pktgen_fops = {
-       .owner    = THIS_MODULE,
-       .open     = pgctrl_open,
-        .read     = seq_read,
-       .llseek   = seq_lseek,
-        .write    = pgctrl_write,
-       .release  = single_release,
+       .owner   = THIS_MODULE,
+       .open    = pgctrl_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .write   = pgctrl_write,
+       .release = single_release,
 };
 
 static int pktgen_if_show(struct seq_file *seq, void *v)
 {
        int i;
-        struct pktgen_dev *pkt_dev = seq->private;
-        __u64 sa;
-        __u64 stopped;
-        __u64 now = getCurUs();
-        
-       seq_printf(seq, "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
-                  (unsigned long long) pkt_dev->count,
-                  pkt_dev->min_pkt_size, pkt_dev->max_pkt_size);
+       struct pktgen_dev *pkt_dev = seq->private;
+       __u64 sa;
+       __u64 stopped;
+       __u64 now = getCurUs();
+
+       seq_printf(seq,
+                  "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
+                  (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size,
+                  pkt_dev->max_pkt_size);
+
+       seq_printf(seq,
+                  "     frags: %d  delay: %u  clone_skb: %d  ifname: %s\n",
+                  pkt_dev->nfrags,
+                  1000 * pkt_dev->delay_us + pkt_dev->delay_ns,
+                  pkt_dev->clone_skb, pkt_dev->ifname);
+
+       seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
+                  pkt_dev->lflow);
+
+       if (pkt_dev->flags & F_IPV6) {
+               char b1[128], b2[128], b3[128];
+               fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr);
+               fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr);
+               fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr);
+               seq_printf(seq,
+                          "     saddr: %s  min_saddr: %s  max_saddr: %s\n", b1,
+                          b2, b3);
+
+               fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr);
+               fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr);
+               fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr);
+               seq_printf(seq,
+                          "     daddr: %s  min_daddr: %s  max_daddr: %s\n", b1,
+                          b2, b3);
+
+       } else
+               seq_printf(seq,
+                          "     dst_min: %s  dst_max: %s\n     src_min: %s  src_max: %s\n",
+                          pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min,
+                          pkt_dev->src_max);
 
-       seq_printf(seq, "     frags: %d  delay: %u  clone_skb: %d  ifname: %s\n",
-                  pkt_dev->nfrags, 1000*pkt_dev->delay_us+pkt_dev->delay_ns, pkt_dev->clone_skb, pkt_dev->ifname);
+       seq_puts(seq, "     src_mac: ");
 
-       seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow);
+       if (is_zero_ether_addr(pkt_dev->src_mac))
+               for (i = 0; i < 6; i++)
+                       seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i],
+                                  i == 5 ? "  " : ":");
+       else
+               for (i = 0; i < 6; i++)
+                       seq_printf(seq, "%02X%s", pkt_dev->src_mac[i],
+                                  i == 5 ? "  " : ":");
+
+       seq_printf(seq, "dst_mac: ");
+       for (i = 0; i < 6; i++)
+               seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i],
+                          i == 5 ? "\n" : ":");
+
+       seq_printf(seq,
+                  "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
+                  pkt_dev->udp_src_min, pkt_dev->udp_src_max,
+                  pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);
+
+       seq_printf(seq,
+                  "     src_mac_count: %d  dst_mac_count: %d \n     Flags: ",
+                  pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
 
+       if (pkt_dev->flags & F_IPV6)
+               seq_printf(seq, "IPV6  ");
 
-       if(pkt_dev->flags & F_IPV6) {
-               char b1[128], b2[128], b3[128];
-               fmt_ip6(b1,  pkt_dev->in6_saddr.s6_addr);
-               fmt_ip6(b2,  pkt_dev->min_in6_saddr.s6_addr);
-               fmt_ip6(b3,  pkt_dev->max_in6_saddr.s6_addr);
-               seq_printf(seq, "     saddr: %s  min_saddr: %s  max_saddr: %s\n", b1, b2, b3);
+       if (pkt_dev->flags & F_IPSRC_RND)
+               seq_printf(seq, "IPSRC_RND  ");
 
-               fmt_ip6(b1,  pkt_dev->in6_daddr.s6_addr);
-               fmt_ip6(b2,  pkt_dev->min_in6_daddr.s6_addr);
-               fmt_ip6(b3,  pkt_dev->max_in6_daddr.s6_addr);
-               seq_printf(seq, "     daddr: %s  min_daddr: %s  max_daddr: %s\n", b1, b2, b3);
+       if (pkt_dev->flags & F_IPDST_RND)
+               seq_printf(seq, "IPDST_RND  ");
 
-       } 
-       else 
-               seq_printf(seq,"     dst_min: %s  dst_max: %s\n     src_min: %s  src_max: %s\n",
-                          pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, pkt_dev->src_max);
+       if (pkt_dev->flags & F_TXSIZE_RND)
+               seq_printf(seq, "TXSIZE_RND  ");
 
-       seq_puts(seq, "     src_mac: ");
+       if (pkt_dev->flags & F_UDPSRC_RND)
+               seq_printf(seq, "UDPSRC_RND  ");
 
-       if (is_zero_ether_addr(pkt_dev->src_mac))
-               for (i = 0; i < 6; i++) 
-                       seq_printf(seq,  "%02X%s", pkt_dev->odev->dev_addr[i], i == 5 ? "  " : ":");
-       else 
-               for (i = 0; i < 6; i++) 
-                       seq_printf(seq,  "%02X%s", pkt_dev->src_mac[i], i == 5 ? "  " : ":");
+       if (pkt_dev->flags & F_UDPDST_RND)
+               seq_printf(seq, "UDPDST_RND  ");
 
-        seq_printf(seq,  "dst_mac: ");
-       for (i = 0; i < 6; i++) 
-               seq_printf(seq,  "%02X%s", pkt_dev->dst_mac[i], i == 5 ? "\n" : ":");
+       if (pkt_dev->flags & F_MACSRC_RND)
+               seq_printf(seq, "MACSRC_RND  ");
 
-        seq_printf(seq,  "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
-                  pkt_dev->udp_src_min, pkt_dev->udp_src_max, pkt_dev->udp_dst_min,
-                  pkt_dev->udp_dst_max);
+       if (pkt_dev->flags & F_MACDST_RND)
+               seq_printf(seq, "MACDST_RND  ");
 
-        seq_printf(seq,  "     src_mac_count: %d  dst_mac_count: %d \n     Flags: ",
-                  pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
+       seq_puts(seq, "\n");
+
+       sa = pkt_dev->started_at;
+       stopped = pkt_dev->stopped_at;
+       if (pkt_dev->running)
+               stopped = now;  /* not really stopped, more like last-running-at */
 
+       seq_printf(seq,
+                  "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %lluus  stopped: %lluus idle: %lluus\n",
+                  (unsigned long long)pkt_dev->sofar,
+                  (unsigned long long)pkt_dev->errors, (unsigned long long)sa,
+                  (unsigned long long)stopped,
+                  (unsigned long long)pkt_dev->idle_acc);
 
-        if (pkt_dev->flags &  F_IPV6) 
-                seq_printf(seq,  "IPV6  ");
-
-        if (pkt_dev->flags &  F_IPSRC_RND) 
-                seq_printf(seq,  "IPSRC_RND  ");
-
-        if (pkt_dev->flags & F_IPDST_RND) 
-                seq_printf(seq,  "IPDST_RND  ");
-        
-        if (pkt_dev->flags & F_TXSIZE_RND) 
-                seq_printf(seq,  "TXSIZE_RND  ");
-        
-        if (pkt_dev->flags & F_UDPSRC_RND) 
-                seq_printf(seq,  "UDPSRC_RND  ");
-        
-        if (pkt_dev->flags & F_UDPDST_RND) 
-                seq_printf(seq,  "UDPDST_RND  ");
-        
-        if (pkt_dev->flags & F_MACSRC_RND) 
-                seq_printf(seq,  "MACSRC_RND  ");
-        
-        if (pkt_dev->flags & F_MACDST_RND) 
-                seq_printf(seq,  "MACDST_RND  ");
-
-        
-        seq_puts(seq,  "\n");
-        
-        sa = pkt_dev->started_at;
-        stopped = pkt_dev->stopped_at;
-        if (pkt_dev->running) 
-                stopped = now; /* not really stopped, more like last-running-at */
-        
-        seq_printf(seq,  "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %lluus  stopped: %lluus idle: %lluus\n",
-                  (unsigned long long) pkt_dev->sofar,
-                  (unsigned long long) pkt_dev->errors,
-                  (unsigned long long) sa,
-                  (unsigned long long) stopped,
-                  (unsigned long long) pkt_dev->idle_acc);
-
-        seq_printf(seq,  "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
+       seq_printf(seq,
+                  "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
                   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
                   pkt_dev->cur_src_mac_offset);
 
-       if(pkt_dev->flags & F_IPV6) {
+       if (pkt_dev->flags & F_IPV6) {
                char b1[128], b2[128];
-               fmt_ip6(b1,  pkt_dev->cur_in6_daddr.s6_addr);
-               fmt_ip6(b2,  pkt_dev->cur_in6_saddr.s6_addr);
-               seq_printf(seq,  "     cur_saddr: %s  cur_daddr: %s\n", b2, b1);
-       } 
-       else 
-               seq_printf(seq,  "     cur_saddr: 0x%x  cur_daddr: 0x%x\n",
+               fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr);
+               fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr);
+               seq_printf(seq, "     cur_saddr: %s  cur_daddr: %s\n", b2, b1);
+       } else
+               seq_printf(seq, "     cur_saddr: 0x%x  cur_daddr: 0x%x\n",
                           pkt_dev->cur_saddr, pkt_dev->cur_daddr);
 
-
-       seq_printf(seq,  "     cur_udp_dst: %d  cur_udp_src: %d\n",
+       seq_printf(seq, "     cur_udp_dst: %d  cur_udp_src: %d\n",
                   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);
 
-       seq_printf(seq,  "     flows: %u\n", pkt_dev->nflows);
+       seq_printf(seq, "     flows: %u\n", pkt_dev->nflows);
 
        if (pkt_dev->result[0])
-               seq_printf(seq,  "Result: %s\n", pkt_dev->result);
+               seq_printf(seq, "Result: %s\n", pkt_dev->result);
        else
-               seq_printf(seq,  "Result: Idle\n");
+               seq_printf(seq, "Result: Idle\n");
 
        return 0;
 }
 
-
-static int count_trail_chars(const char __user *user_buffer, unsigned int maxlen)
+static int count_trail_chars(const char __user * user_buffer,
+                            unsigned int maxlen)
 {
        int i;
 
        for (i = 0; i < maxlen; i++) {
-                char c;
-                if (get_user(c, &user_buffer[i]))
-                        return -EFAULT;
-                switch (c) {
+               char c;
+               if (get_user(c, &user_buffer[i]))
+                       return -EFAULT;
+               switch (c) {
                case '\"':
                case '\n':
                case '\r':
@@ -706,34 +716,34 @@ done:
        return i;
 }
 
-static unsigned long num_arg(const char __user *user_buffer, unsigned long maxlen, 
-                            unsigned long *num)
+static unsigned long num_arg(const char __user * user_buffer,
+                            unsigned long maxlen, unsigned long *num)
 {
        int i = 0;
        *num = 0;
-  
-       for(; i < maxlen; i++) {
-                char c;
-                if (get_user(c, &user_buffer[i]))
-                        return -EFAULT;
-                if ((c >= '0') && (c <= '9')) {
+
+       for (; i < maxlen; i++) {
+               char c;
+               if (get_user(c, &user_buffer[i]))
+                       return -EFAULT;
+               if ((c >= '0') && (c <= '9')) {
                        *num *= 10;
-                       *num += c -'0';
+                       *num += c - '0';
                } else
                        break;
        }
        return i;
 }
 
-static int strn_len(const char __user *user_buffer, unsigned int maxlen)
+static int strn_len(const char __user * user_buffer, unsigned int maxlen)
 {
        int i = 0;
 
-       for(; i < maxlen; i++) {
-                char c;
-                if (get_user(c, &user_buffer[i]))
-                        return -EFAULT;
-                switch (c) {
+       for (; i < maxlen; i++) {
+               char c;
+               if (get_user(c, &user_buffer[i]))
+                       return -EFAULT;
+               switch (c) {
                case '\"':
                case '\n':
                case '\r':
@@ -746,119 +756,133 @@ static int strn_len(const char __user *user_buffer, unsigned int maxlen)
                };
        }
 done_str:
-
        return i;
 }
 
-static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer,
-                              size_t count, loff_t *offset)
+static ssize_t pktgen_if_write(struct file *file,
+                              const char __user * user_buffer, size_t count,
+                              loff_t * offset)
 {
-       struct seq_file *seq = (struct seq_file *) file->private_data;
-        struct pktgen_dev *pkt_dev = seq->private;
+       struct seq_file *seq = (struct seq_file *)file->private_data;
+       struct pktgen_dev *pkt_dev = seq->private;
        int i = 0, max, len;
        char name[16], valstr[32];
        unsigned long value = 0;
-        char* pg_result = NULL;
-        int tmp = 0;
+       char *pg_result = NULL;
+       int tmp = 0;
        char buf[128];
-        
-        pg_result = &(pkt_dev->result[0]);
-        
+
+       pg_result = &(pkt_dev->result[0]);
+
        if (count < 1) {
                printk("pktgen: wrong command format\n");
                return -EINVAL;
        }
-  
+
        max = count - i;
        tmp = count_trail_chars(&user_buffer[i], max);
-        if (tmp < 0) { 
+       if (tmp < 0) {
                printk("pktgen: illegal format\n");
-               return tmp; 
+               return tmp;
        }
-        i += tmp;
-        
+       i += tmp;
+
        /* Read variable name */
 
        len = strn_len(&user_buffer[i], sizeof(name) - 1);
-        if (len < 0) { return len; }
+       if (len < 0) {
+               return len;
+       }
        memset(name, 0, sizeof(name));
-       if (copy_from_user(name, &user_buffer[i], len) )
+       if (copy_from_user(name, &user_buffer[i], len))
                return -EFAULT;
        i += len;
-  
-       max = count -i;
+
+       max = count - i;
        len = count_trail_chars(&user_buffer[i], max);
-        if (len < 0) 
-                return len;
-        
+       if (len < 0)
+               return len;
+
        i += len;
 
        if (debug) {
-                char tb[count + 1];
-                if (copy_from_user(tb, user_buffer, count))
+               char tb[count + 1];
+               if (copy_from_user(tb, user_buffer, count))
                        return -EFAULT;
-                tb[count] = 0;
+               tb[count] = 0;
                printk("pktgen: %s,%lu  buffer -:%s:-\n", name,
-                      (unsigned long) count, tb);
-        }
+                      (unsigned long)count, tb);
+       }
 
        if (!strcmp(name, "min_pkt_size")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-               if (value < 14+20+8)
-                       value = 14+20+8;
-                if (value != pkt_dev->min_pkt_size) {
-                        pkt_dev->min_pkt_size = value;
-                        pkt_dev->cur_pkt_size = value;
-                }
-               sprintf(pg_result, "OK: min_pkt_size=%u", pkt_dev->min_pkt_size);
+               if (value < 14 + 20 + 8)
+                       value = 14 + 20 + 8;
+               if (value != pkt_dev->min_pkt_size) {
+                       pkt_dev->min_pkt_size = value;
+                       pkt_dev->cur_pkt_size = value;
+               }
+               sprintf(pg_result, "OK: min_pkt_size=%u",
+                       pkt_dev->min_pkt_size);
                return count;
        }
 
-        if (!strcmp(name, "max_pkt_size")) {
+       if (!strcmp(name, "max_pkt_size")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-               if (value < 14+20+8)
-                       value = 14+20+8;
-                if (value != pkt_dev->max_pkt_size) {
-                        pkt_dev->max_pkt_size = value;
-                        pkt_dev->cur_pkt_size = value;
-                }
-               sprintf(pg_result, "OK: max_pkt_size=%u", pkt_dev->max_pkt_size);
+               if (value < 14 + 20 + 8)
+                       value = 14 + 20 + 8;
+               if (value != pkt_dev->max_pkt_size) {
+                       pkt_dev->max_pkt_size = value;
+                       pkt_dev->cur_pkt_size = value;
+               }
+               sprintf(pg_result, "OK: max_pkt_size=%u",
+                       pkt_dev->max_pkt_size);
                return count;
        }
 
-        /* Shortcut for min = max */
+       /* Shortcut for min = max */
 
        if (!strcmp(name, "pkt_size")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-               if (value < 14+20+8)
-                       value = 14+20+8;
-                if (value != pkt_dev->min_pkt_size) {
-                        pkt_dev->min_pkt_size = value;
-                        pkt_dev->max_pkt_size = value;
-                        pkt_dev->cur_pkt_size = value;
-                }
+               if (value < 14 + 20 + 8)
+                       value = 14 + 20 + 8;
+               if (value != pkt_dev->min_pkt_size) {
+                       pkt_dev->min_pkt_size = value;
+                       pkt_dev->max_pkt_size = value;
+                       pkt_dev->cur_pkt_size = value;
+               }
                sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size);
                return count;
        }
 
-        if (!strcmp(name, "debug")) {
+       if (!strcmp(name, "debug")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-                debug = value;
+               debug = value;
                sprintf(pg_result, "OK: debug=%u", debug);
                return count;
        }
 
-        if (!strcmp(name, "frags")) {
+       if (!strcmp(name, "frags")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
                pkt_dev->nfrags = value;
                sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags);
@@ -866,7 +890,9 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer
        }
        if (!strcmp(name, "delay")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
                if (value == 0x7FFFFFFF) {
                        pkt_dev->delay_us = 0x7FFFFFFF;
@@ -875,308 +901,347 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer
                        pkt_dev->delay_us = value / 1000;
                        pkt_dev->delay_ns = value % 1000;
                }
-               sprintf(pg_result, "OK: delay=%u", 1000*pkt_dev->delay_us+pkt_dev->delay_ns);
+               sprintf(pg_result, "OK: delay=%u",
+                       1000 * pkt_dev->delay_us + pkt_dev->delay_ns);
                return count;
        }
-       if (!strcmp(name, "udp_src_min")) {
+       if (!strcmp(name, "udp_src_min")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-                if (value != pkt_dev->udp_src_min) {
-                        pkt_dev->udp_src_min = value;
-                        pkt_dev->cur_udp_src = value;
-                }       
+               if (value != pkt_dev->udp_src_min) {
+                       pkt_dev->udp_src_min = value;
+                       pkt_dev->cur_udp_src = value;
+               }
                sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
                return count;
        }
-       if (!strcmp(name, "udp_dst_min")) {
+       if (!strcmp(name, "udp_dst_min")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-                if (value != pkt_dev->udp_dst_min) {
-                        pkt_dev->udp_dst_min = value;
-                        pkt_dev->cur_udp_dst = value;
-                }
+               if (value != pkt_dev->udp_dst_min) {
+                       pkt_dev->udp_dst_min = value;
+                       pkt_dev->cur_udp_dst = value;
+               }
                sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
                return count;
        }
-       if (!strcmp(name, "udp_src_max")) {
+       if (!strcmp(name, "udp_src_max")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-                if (value != pkt_dev->udp_src_max) {
-                        pkt_dev->udp_src_max = value;
-                        pkt_dev->cur_udp_src = value;
-                }
+               if (value != pkt_dev->udp_src_max) {
+                       pkt_dev->udp_src_max = value;
+                       pkt_dev->cur_udp_src = value;
+               }
                sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
                return count;
        }
-       if (!strcmp(name, "udp_dst_max")) {
+       if (!strcmp(name, "udp_dst_max")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-                if (value != pkt_dev->udp_dst_max) {
-                        pkt_dev->udp_dst_max = value;
-                        pkt_dev->cur_udp_dst = value;
-                }
+               if (value != pkt_dev->udp_dst_max) {
+                       pkt_dev->udp_dst_max = value;
+                       pkt_dev->cur_udp_dst = value;
+               }
                sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max);
                return count;
        }
        if (!strcmp(name, "clone_skb")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
-                pkt_dev->clone_skb = value;
-       
+               pkt_dev->clone_skb = value;
+
                sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb);
                return count;
        }
        if (!strcmp(name, "count")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
                pkt_dev->count = value;
                sprintf(pg_result, "OK: count=%llu",
-                       (unsigned long long) pkt_dev->count);
+                       (unsigned long long)pkt_dev->count);
                return count;
        }
        if (!strcmp(name, "src_mac_count")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
                if (pkt_dev->src_mac_count != value) {
-                        pkt_dev->src_mac_count = value;
-                        pkt_dev->cur_src_mac_offset = 0;
-                }
-               sprintf(pg_result, "OK: src_mac_count=%d", pkt_dev->src_mac_count);
+                       pkt_dev->src_mac_count = value;
+                       pkt_dev->cur_src_mac_offset = 0;
+               }
+               sprintf(pg_result, "OK: src_mac_count=%d",
+                       pkt_dev->src_mac_count);
                return count;
        }
        if (!strcmp(name, "dst_mac_count")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
                if (pkt_dev->dst_mac_count != value) {
-                        pkt_dev->dst_mac_count = value;
-                        pkt_dev->cur_dst_mac_offset = 0;
-                }
-               sprintf(pg_result, "OK: dst_mac_count=%d", pkt_dev->dst_mac_count);
+                       pkt_dev->dst_mac_count = value;
+                       pkt_dev->cur_dst_mac_offset = 0;
+               }
+               sprintf(pg_result, "OK: dst_mac_count=%d",
+                       pkt_dev->dst_mac_count);
                return count;
        }
        if (!strcmp(name, "flag")) {
-                char f[32];
-                memset(f, 0, 32);
+               char f[32];
+               memset(f, 0, 32);
                len = strn_len(&user_buffer[i], sizeof(f) - 1);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                if (copy_from_user(f, &user_buffer[i], len))
                        return -EFAULT;
                i += len;
-                if (strcmp(f, "IPSRC_RND") == 0) 
-                        pkt_dev->flags |= F_IPSRC_RND;
-                
-                else if (strcmp(f, "!IPSRC_RND") == 0) 
-                        pkt_dev->flags &= ~F_IPSRC_RND;
-                
-                else if (strcmp(f, "TXSIZE_RND") == 0) 
-                        pkt_dev->flags |= F_TXSIZE_RND;
-                
-                else if (strcmp(f, "!TXSIZE_RND") == 0) 
-                        pkt_dev->flags &= ~F_TXSIZE_RND;
-                
-                else if (strcmp(f, "IPDST_RND") == 0) 
-                        pkt_dev->flags |= F_IPDST_RND;
-                
-                else if (strcmp(f, "!IPDST_RND") == 0) 
-                        pkt_dev->flags &= ~F_IPDST_RND;
-                
-                else if (strcmp(f, "UDPSRC_RND") == 0) 
-                        pkt_dev->flags |= F_UDPSRC_RND;
-                
-                else if (strcmp(f, "!UDPSRC_RND") == 0) 
-                        pkt_dev->flags &= ~F_UDPSRC_RND;
-                
-                else if (strcmp(f, "UDPDST_RND") == 0) 
-                        pkt_dev->flags |= F_UDPDST_RND;
-                
-                else if (strcmp(f, "!UDPDST_RND") == 0) 
-                        pkt_dev->flags &= ~F_UDPDST_RND;
-                
-                else if (strcmp(f, "MACSRC_RND") == 0) 
-                        pkt_dev->flags |= F_MACSRC_RND;
-                
-                else if (strcmp(f, "!MACSRC_RND") == 0) 
-                        pkt_dev->flags &= ~F_MACSRC_RND;
-                
-                else if (strcmp(f, "MACDST_RND") == 0) 
-                        pkt_dev->flags |= F_MACDST_RND;
-                
-                else if (strcmp(f, "!MACDST_RND") == 0) 
-                        pkt_dev->flags &= ~F_MACDST_RND;
-                
-                else {
-                        sprintf(pg_result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
-                                f,
-                                "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
-                        return count;
-                }
+               if (strcmp(f, "IPSRC_RND") == 0)
+                       pkt_dev->flags |= F_IPSRC_RND;
+
+               else if (strcmp(f, "!IPSRC_RND") == 0)
+                       pkt_dev->flags &= ~F_IPSRC_RND;
+
+               else if (strcmp(f, "TXSIZE_RND") == 0)
+                       pkt_dev->flags |= F_TXSIZE_RND;
+
+               else if (strcmp(f, "!TXSIZE_RND") == 0)
+                       pkt_dev->flags &= ~F_TXSIZE_RND;
+
+               else if (strcmp(f, "IPDST_RND") == 0)
+                       pkt_dev->flags |= F_IPDST_RND;
+
+               else if (strcmp(f, "!IPDST_RND") == 0)
+                       pkt_dev->flags &= ~F_IPDST_RND;
+
+               else if (strcmp(f, "UDPSRC_RND") == 0)
+                       pkt_dev->flags |= F_UDPSRC_RND;
+
+               else if (strcmp(f, "!UDPSRC_RND") == 0)
+                       pkt_dev->flags &= ~F_UDPSRC_RND;
+
+               else if (strcmp(f, "UDPDST_RND") == 0)
+                       pkt_dev->flags |= F_UDPDST_RND;
+
+               else if (strcmp(f, "!UDPDST_RND") == 0)
+                       pkt_dev->flags &= ~F_UDPDST_RND;
+
+               else if (strcmp(f, "MACSRC_RND") == 0)
+                       pkt_dev->flags |= F_MACSRC_RND;
+
+               else if (strcmp(f, "!MACSRC_RND") == 0)
+                       pkt_dev->flags &= ~F_MACSRC_RND;
+
+               else if (strcmp(f, "MACDST_RND") == 0)
+                       pkt_dev->flags |= F_MACDST_RND;
+
+               else if (strcmp(f, "!MACDST_RND") == 0)
+                       pkt_dev->flags &= ~F_MACDST_RND;
+
+               else {
+                       sprintf(pg_result,
+                               "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
+                               f,
+                               "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
+                       return count;
+               }
                sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
                return count;
        }
        if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
                len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
 
-                if (copy_from_user(buf, &user_buffer[i], len))
+               if (copy_from_user(buf, &user_buffer[i], len))
                        return -EFAULT;
-                buf[len] = 0;
-                if (strcmp(buf, pkt_dev->dst_min) != 0) {
-                        memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min));
-                        strncpy(pkt_dev->dst_min, buf, len);
-                        pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
-                        pkt_dev->cur_daddr = pkt_dev->daddr_min;
-                }
-                if(debug)
-                        printk("pktgen: dst_min set to: %s\n", pkt_dev->dst_min);
-                i += len;
+               buf[len] = 0;
+               if (strcmp(buf, pkt_dev->dst_min) != 0) {
+                       memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min));
+                       strncpy(pkt_dev->dst_min, buf, len);
+                       pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
+                       pkt_dev->cur_daddr = pkt_dev->daddr_min;
+               }
+               if (debug)
+                       printk("pktgen: dst_min set to: %s\n",
+                              pkt_dev->dst_min);
+               i += len;
                sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
                return count;
        }
        if (!strcmp(name, "dst_max")) {
                len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
 
-                if (copy_from_user(buf, &user_buffer[i], len))
+               if (copy_from_user(buf, &user_buffer[i], len))
                        return -EFAULT;
 
-                buf[len] = 0;
-                if (strcmp(buf, pkt_dev->dst_max) != 0) {
-                        memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max));
-                        strncpy(pkt_dev->dst_max, buf, len);
-                        pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
-                        pkt_dev->cur_daddr = pkt_dev->daddr_max;
-                }
-               if(debug)
-                       printk("pktgen: dst_max set to: %s\n", pkt_dev->dst_max);
+               buf[len] = 0;
+               if (strcmp(buf, pkt_dev->dst_max) != 0) {
+                       memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max));
+                       strncpy(pkt_dev->dst_max, buf, len);
+                       pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
+                       pkt_dev->cur_daddr = pkt_dev->daddr_max;
+               }
+               if (debug)
+                       printk("pktgen: dst_max set to: %s\n",
+                              pkt_dev->dst_max);
                i += len;
                sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
                return count;
        }
        if (!strcmp(name, "dst6")) {
                len = strn_len(&user_buffer[i], sizeof(buf) - 1);
-                if (len < 0) return len; 
+               if (len < 0)
+                       return len;
 
                pkt_dev->flags |= F_IPV6;
 
-                if (copy_from_user(buf, &user_buffer[i], len))
+               if (copy_from_user(buf, &user_buffer[i], len))
                        return -EFAULT;
-                buf[len] = 0;
+               buf[len] = 0;
 
                scan_ip6(buf, pkt_dev->in6_daddr.s6_addr);
-               fmt_ip6(buf,  pkt_dev->in6_daddr.s6_addr);
+               fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr);
 
                ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);
 
-                if(debug) 
+               if (debug)
                        printk("pktgen: dst6 set to: %s\n", buf);
 
-                i += len;
+               i += len;
                sprintf(pg_result, "OK: dst6=%s", buf);
                return count;
        }
        if (!strcmp(name, "dst6_min")) {
                len = strn_len(&user_buffer[i], sizeof(buf) - 1);
-                if (len < 0) return len; 
+               if (len < 0)
+                       return len;
 
                pkt_dev->flags |= F_IPV6;
 
-                if (copy_from_user(buf, &user_buffer[i], len))
+               if (copy_from_user(buf, &user_buffer[i], len))
                        return -EFAULT;
-                buf[len] = 0;
+               buf[len] = 0;
 
                scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
-               fmt_ip6(buf,  pkt_dev->min_in6_daddr.s6_addr);
+               fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
 
-               ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->min_in6_daddr);
-                if(debug) 
+               ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
+                              &pkt_dev->min_in6_daddr);
+               if (debug)
                        printk("pktgen: dst6_min set to: %s\n", buf);
 
-                i += len;
+               i += len;
                sprintf(pg_result, "OK: dst6_min=%s", buf);
                return count;
        }
        if (!strcmp(name, "dst6_max")) {
                len = strn_len(&user_buffer[i], sizeof(buf) - 1);
-                if (len < 0) return len; 
+               if (len < 0)
+                       return len;
 
                pkt_dev->flags |= F_IPV6;
 
-                if (copy_from_user(buf, &user_buffer[i], len))
+               if (copy_from_user(buf, &user_buffer[i], len))
                        return -EFAULT;
-                buf[len] = 0;
+               buf[len] = 0;
 
                scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
-               fmt_ip6(buf,  pkt_dev->max_in6_daddr.s6_addr);
+               fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
 
-                if(debug) 
+               if (debug)
                        printk("pktgen: dst6_max set to: %s\n", buf);
 
-                i += len;
+               i += len;
                sprintf(pg_result, "OK: dst6_max=%s", buf);
                return count;
        }
        if (!strcmp(name, "src6")) {
                len = strn_len(&user_buffer[i], sizeof(buf) - 1);
-                if (len < 0) return len; 
+               if (len < 0)
+                       return len;
 
                pkt_dev->flags |= F_IPV6;
 
-                if (copy_from_user(buf, &user_buffer[i], len))
+               if (copy_from_user(buf, &user_buffer[i], len))
                        return -EFAULT;
-                buf[len] = 0;
+               buf[len] = 0;
 
                scan_ip6(buf, pkt_dev->in6_saddr.s6_addr);
-               fmt_ip6(buf,  pkt_dev->in6_saddr.s6_addr);
+               fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr);
 
                ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);
 
-                if(debug) 
+               if (debug)
                        printk("pktgen: src6 set to: %s\n", buf);
-               
-                i += len;
+
+               i += len;
                sprintf(pg_result, "OK: src6=%s", buf);
                return count;
        }
        if (!strcmp(name, "src_min")) {
                len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
-                if (len < 0) { return len; }
-                if (copy_from_user(buf, &user_buffer[i], len))
+               if (len < 0) {
+                       return len;
+               }
+               if (copy_from_user(buf, &user_buffer[i], len))
                        return -EFAULT;
-                buf[len] = 0;
-                if (strcmp(buf, pkt_dev->src_min) != 0) {
-                        memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min));
-                        strncpy(pkt_dev->src_min, buf, len);
-                        pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
-                        pkt_dev->cur_saddr = pkt_dev->saddr_min;
-                }
-               if(debug)
-                       printk("pktgen: src_min set to: %s\n", pkt_dev->src_min);
+               buf[len] = 0;
+               if (strcmp(buf, pkt_dev->src_min) != 0) {
+                       memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min));
+                       strncpy(pkt_dev->src_min, buf, len);
+                       pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
+                       pkt_dev->cur_saddr = pkt_dev->saddr_min;
+               }
+               if (debug)
+                       printk("pktgen: src_min set to: %s\n",
+                              pkt_dev->src_min);
                i += len;
                sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
                return count;
        }
        if (!strcmp(name, "src_max")) {
                len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
-                if (len < 0) { return len; }
-                if (copy_from_user(buf, &user_buffer[i], len))
+               if (len < 0) {
+                       return len;
+               }
+               if (copy_from_user(buf, &user_buffer[i], len))
                        return -EFAULT;
-                buf[len] = 0;
-                if (strcmp(buf, pkt_dev->src_max) != 0) {
-                        memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max));
-                        strncpy(pkt_dev->src_max, buf, len);
-                        pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
-                        pkt_dev->cur_saddr = pkt_dev->saddr_max;
-                }
-               if(debug)
-                       printk("pktgen: src_max set to: %s\n", pkt_dev->src_max);
+               buf[len] = 0;
+               if (strcmp(buf, pkt_dev->src_max) != 0) {
+                       memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max));
+                       strncpy(pkt_dev->src_max, buf, len);
+                       pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
+                       pkt_dev->cur_saddr = pkt_dev->saddr_max;
+               }
+               if (debug)
+                       printk("pktgen: src_max set to: %s\n",
+                              pkt_dev->src_max);
                i += len;
                sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
                return count;
@@ -1186,15 +1251,17 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer
                unsigned char old_dmac[ETH_ALEN];
                unsigned char *m = pkt_dev->dst_mac;
                memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN);
-                
+
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                memset(valstr, 0, sizeof(valstr));
-               ifcopy_from_user(valstr, &user_buffer[i], len))
+               if (copy_from_user(valstr, &user_buffer[i], len))
                        return -EFAULT;
                i += len;
 
-               for(*m = 0;*v && m < pkt_dev->dst_mac + 6; v++) {
+               for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
                        if (*v >= '0' && *v <= '9') {
                                *m *= 16;
                                *m += *v - '0';
@@ -1216,7 +1283,7 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer
                /* Set up Dest MAC */
                if (compare_ether_addr(old_dmac, pkt_dev->dst_mac))
                        memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
-                
+
                sprintf(pg_result, "OK: dstmac");
                return count;
        }
@@ -1225,13 +1292,15 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer
                unsigned char *m = pkt_dev->src_mac;
 
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                memset(valstr, 0, sizeof(valstr));
-               if( copy_from_user(valstr, &user_buffer[i], len)) 
+               if (copy_from_user(valstr, &user_buffer[i], len))
                        return -EFAULT;
                i += len;
 
-               for(*m = 0;*v && m < pkt_dev->src_mac + 6; v++) {
+               for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
                        if (*v >= '0' && *v <= '9') {
                                *m *= 16;
                                *m += *v - '0';
@@ -1248,21 +1317,23 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer
                                m++;
                                *m = 0;
                        }
-               }         
+               }
 
-                sprintf(pg_result, "OK: srcmac");
+               sprintf(pg_result, "OK: srcmac");
                return count;
        }
 
-        if (!strcmp(name, "clear_counters")) {
-                pktgen_clear_counters(pkt_dev);
-                sprintf(pg_result, "OK: Clearing counters.\n");
-                return count;
-        }
+       if (!strcmp(name, "clear_counters")) {
+               pktgen_clear_counters(pkt_dev);
+               sprintf(pg_result, "OK: Clearing counters.\n");
+               return count;
+       }
 
        if (!strcmp(name, "flows")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
                if (value > MAX_CFLOWS)
                        value = MAX_CFLOWS;
@@ -1274,13 +1345,15 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer
 
        if (!strcmp(name, "flowlen")) {
                len = num_arg(&user_buffer[i], 10, &value);
-                if (len < 0) { return len; }
+               if (len < 0) {
+                       return len;
+               }
                i += len;
                pkt_dev->lflow = value;
                sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
                return count;
        }
-        
+
        sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
        return -EINVAL;
 }
@@ -1291,35 +1364,35 @@ static int pktgen_if_open(struct inode *inode, struct file *file)
 }
 
 static struct file_operations pktgen_if_fops = {
-       .owner    = THIS_MODULE,
-       .open     = pktgen_if_open,
-        .read     = seq_read,
-       .llseek   = seq_lseek,
-        .write    = pktgen_if_write,
-       .release  = single_release,
+       .owner   = THIS_MODULE,
+       .open    = pktgen_if_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .write   = pktgen_if_write,
+       .release = single_release,
 };
 
 static int pktgen_thread_show(struct seq_file *seq, void *v)
 {
-        struct pktgen_thread *t = seq->private;
-        struct pktgen_dev *pkt_dev = NULL;
+       struct pktgen_thread *t = seq->private;
+       struct pktgen_dev *pkt_dev;
 
        BUG_ON(!t);
 
        seq_printf(seq, "Name: %s  max_before_softirq: %d\n",
-                     t->name, t->max_before_softirq);
+                  t->name, t->max_before_softirq);
+
+       seq_printf(seq, "Running: ");
 
-        seq_printf(seq, "Running: ");
-        
-        if_lock(t);
-        for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) 
-               if(pkt_dev->running)
+       if_lock(t);
+       list_for_each_entry(pkt_dev, &t->if_list, list)
+               if (pkt_dev->running)
                        seq_printf(seq, "%s ", pkt_dev->ifname);
-        
-        seq_printf(seq, "\nStopped: ");
 
-        for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) 
-               if(!pkt_dev->running)
+       seq_printf(seq, "\nStopped: ");
+
+       list_for_each_entry(pkt_dev, &t->if_list, list)
+               if (!pkt_dev->running)
                        seq_printf(seq, "%s ", pkt_dev->ifname);
 
        if (t->result[0])
@@ -1327,30 +1400,30 @@ static int pktgen_thread_show(struct seq_file *seq, void *v)
        else
                seq_printf(seq, "\nResult: NA\n");
 
-        if_unlock(t);
+       if_unlock(t);
 
        return 0;
 }
 
 static ssize_t pktgen_thread_write(struct file *file,
-                                  const char __user *user_buffer,
-                                  size_t count, loff_t *offset)
+                                  const char __user * user_buffer,
+                                  size_t count, loff_t * offset)
 {
-       struct seq_file *seq = (struct seq_file *) file->private_data;
-        struct pktgen_thread *t = seq->private;
+       struct seq_file *seq = (struct seq_file *)file->private_data;
+       struct pktgen_thread *t = seq->private;
        int i = 0, max, len, ret;
        char name[40];
-        char *pg_result;
-        unsigned long value = 0;
+       char *pg_result;
+       unsigned long value = 0;
 
        if (count < 1) {
-               //      sprintf(pg_result, "Wrong command format");
+               //      sprintf(pg_result, "Wrong command format");
                return -EINVAL;
        }
 
        max = count - i;
-        len = count_trail_chars(&user_buffer[i], max);
-        if (len < 0)
+       len = count_trail_chars(&user_buffer[i], max);
+       if (len < 0)
                return len;
 
        i += len;
@@ -1358,26 +1431,25 @@ static ssize_t pktgen_thread_write(struct file *file,
        /* Read variable name */
 
        len = strn_len(&user_buffer[i], sizeof(name) - 1);
-        if (len < 0)
+       if (len < 0)
                return len;
-       
+
        memset(name, 0, sizeof(name));
        if (copy_from_user(name, &user_buffer[i], len))
                return -EFAULT;
        i += len;
 
-       max = count -i;
+       max = count - i;
        len = count_trail_chars(&user_buffer[i], max);
-        if (len < 0)
+       if (len < 0)
                return len;
 
        i += len;
 
        if (debug)
-               printk("pktgen: t=%s, count=%lu\n", name,
-                      (unsigned long) count);
+               printk("pktgen: t=%s, count=%lu\n", name, (unsigned long)count);
 
-       if(!t) {
+       if (!t) {
                printk("pktgen: ERROR: No thread\n");
                ret = -EINVAL;
                goto out;
@@ -1385,48 +1457,47 @@ static ssize_t pktgen_thread_write(struct file *file,
 
        pg_result = &(t->result[0]);
 
-        if (!strcmp(name, "add_device")) {
-                char f[32];
-                memset(f, 0, 32);
+       if (!strcmp(name, "add_device")) {
+               char f[32];
+               memset(f, 0, 32);
                len = strn_len(&user_buffer[i], sizeof(f) - 1);
-                if (len < 0) { 
-                       ret = len; 
+               if (len < 0) {
+                       ret = len;
                        goto out;
                }
-               if( copy_from_user(f, &user_buffer[i], len) )
+               if (copy_from_user(f, &user_buffer[i], len))
                        return -EFAULT;
                i += len;
-               thread_lock();
-                pktgen_add_device(t, f);
-               thread_unlock();
-                ret = count;
-                sprintf(pg_result, "OK: add_device=%s", f);
+               mutex_lock(&pktgen_thread_lock);
+               pktgen_add_device(t, f);
+               mutex_unlock(&pktgen_thread_lock);
+               ret = count;
+               sprintf(pg_result, "OK: add_device=%s", f);
                goto out;
        }
 
-        if (!strcmp(name, "rem_device_all")) {
-               thread_lock();
-               t->control |= T_REMDEV;
-               thread_unlock();
-               schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
+       if (!strcmp(name, "rem_device_all")) {
+               mutex_lock(&pktgen_thread_lock);
+               t->control |= T_REMDEVALL;
+               mutex_unlock(&pktgen_thread_lock);
+               schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
                ret = count;
-                sprintf(pg_result, "OK: rem_device_all");
+               sprintf(pg_result, "OK: rem_device_all");
                goto out;
        }
 
-        if (!strcmp(name, "max_before_softirq")) {
-                len = num_arg(&user_buffer[i], 10, &value);
-               thread_lock();
-                t->max_before_softirq = value;
-               thread_unlock();
-                ret = count;
-                sprintf(pg_result, "OK: max_before_softirq=%lu", value);
+       if (!strcmp(name, "max_before_softirq")) {
+               len = num_arg(&user_buffer[i], 10, &value);
+               mutex_lock(&pktgen_thread_lock);
+               t->max_before_softirq = value;
+               mutex_unlock(&pktgen_thread_lock);
+               ret = count;
+               sprintf(pg_result, "OK: max_before_softirq=%lu", value);
                goto out;
        }
 
        ret = -EINVAL;
- out:
-
+out:
        return ret;
 }
 
@@ -1436,47 +1507,78 @@ static int pktgen_thread_open(struct inode *inode, struct file *file)
 }
 
 static struct file_operations pktgen_thread_fops = {
-       .owner    = THIS_MODULE,
-       .open     = pktgen_thread_open,
-        .read     = seq_read,
-       .llseek   = seq_lseek,
-        .write    = pktgen_thread_write,
-       .release  = single_release,
+       .owner   = THIS_MODULE,
+       .open    = pktgen_thread_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .write   = pktgen_thread_write,
+       .release = single_release,
 };
 
 /* Think find or remove for NN */
-static struct pktgen_dev *__pktgen_NN_threads(const char* ifname, int remove) 
+static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
 {
        struct pktgen_thread *t;
        struct pktgen_dev *pkt_dev = NULL;
 
-        t = pktgen_threads;
-                
-       while (t) {
+       list_for_each_entry(t, &pktgen_threads, th_list) {
                pkt_dev = pktgen_find_dev(t, ifname);
                if (pkt_dev) {
-                               if(remove) { 
-                                       if_lock(t);
-                                       pktgen_remove_device(t, pkt_dev);
-                                       if_unlock(t);
-                               }
+                       if (remove) {
+                               if_lock(t);
+                               pkt_dev->removal_mark = 1;
+                               t->control |= T_REMDEV;
+                               if_unlock(t);
+                       }
                        break;
                }
-               t = t->next;
        }
-        return pkt_dev;
+       return pkt_dev;
 }
 
-static struct pktgen_dev *pktgen_NN_threads(const char* ifname, int remove) 
+/*
+ * mark a device for removal
+ */
+static int pktgen_mark_device(const char *ifname)
 {
        struct pktgen_dev *pkt_dev = NULL;
-       thread_lock();
-       pkt_dev = __pktgen_NN_threads(ifname, remove);
-        thread_unlock();
-       return pkt_dev;
+       const int max_tries = 10, msec_per_try = 125;
+       int i = 0;
+       int ret = 0;
+
+       mutex_lock(&pktgen_thread_lock);
+       PG_DEBUG(printk("pktgen: pktgen_mark_device marking %s for removal\n",
+                       ifname));
+
+       while (1) {
+
+               pkt_dev = __pktgen_NN_threads(ifname, REMOVE);
+               if (pkt_dev == NULL)
+                       break;  /* success */
+
+               mutex_unlock(&pktgen_thread_lock);
+               PG_DEBUG(printk("pktgen: pktgen_mark_device waiting for %s "
+                               "to disappear....\n", ifname));
+               schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
+               mutex_lock(&pktgen_thread_lock);
+
+               if (++i >= max_tries) {
+                       printk("pktgen_mark_device: timed out after waiting "
+                              "%d msec for device %s to be removed\n",
+                              msec_per_try * i, ifname);
+                       ret = 1;
+                       break;
+               }
+
+       }
+
+       mutex_unlock(&pktgen_thread_lock);
+
+       return ret;
 }
 
-static int pktgen_device_event(struct notifier_block *unused, unsigned long event, void *ptr) 
+static int pktgen_device_event(struct notifier_block *unused,
+                              unsigned long event, void *ptr)
 {
        struct net_device *dev = (struct net_device *)(ptr);
 
@@ -1491,9 +1593,9 @@ static int pktgen_device_event(struct notifier_block *unused, unsigned long even
        case NETDEV_UP:
                /* Ignore for now */
                break;
-               
+
        case NETDEV_UNREGISTER:
-                pktgen_NN_threads(dev->name, REMOVE);
+               pktgen_mark_device(dev->name);
                break;
        };
 
@@ -1502,15 +1604,16 @@ static int pktgen_device_event(struct notifier_block *unused, unsigned long even
 
 /* Associate pktgen_dev with a device. */
 
-static struct net_device* pktgen_setup_dev(struct pktgen_dev *pkt_dev) {
+static struct net_device *pktgen_setup_dev(struct pktgen_dev *pkt_dev)
+{
        struct net_device *odev;
 
        /* Clean old setups */
 
        if (pkt_dev->odev) {
                dev_put(pkt_dev->odev);
-                pkt_dev->odev = NULL;
-        }
+               pkt_dev->odev = NULL;
+       }
 
        odev = dev_get_by_name(pkt_dev->ifname);
 
@@ -1519,7 +1622,8 @@ static struct net_device* pktgen_setup_dev(struct pktgen_dev *pkt_dev) {
                goto out;
        }
        if (odev->type != ARPHRD_ETHER) {
-               printk("pktgen: not an ethernet device: \"%s\"\n", pkt_dev->ifname);
+               printk("pktgen: not an ethernet device: \"%s\"\n",
+                      pkt_dev->ifname);
                goto out_put;
        }
        if (!netif_running(odev)) {
@@ -1527,13 +1631,13 @@ static struct net_device* pktgen_setup_dev(struct pktgen_dev *pkt_dev) {
                goto out_put;
        }
        pkt_dev->odev = odev;
-       
-        return pkt_dev->odev;
+
+       return pkt_dev->odev;
 
 out_put:
        dev_put(odev);
 out:
-       return NULL;
+       return NULL;
 
 }
 
@@ -1543,59 +1647,64 @@ out:
 static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
 {
        /* Try once more, just in case it works now. */
-        if (!pkt_dev->odev) 
-                pktgen_setup_dev(pkt_dev);
-        
-        if (!pkt_dev->odev) {
-                printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n");
-                sprintf(pkt_dev->result, "ERROR: pkt_dev->odev == NULL in setup_inject.\n");
-                return;
-        }
-        
-        /* Default to the interface's mac if not explicitly set. */
+       if (!pkt_dev->odev)
+               pktgen_setup_dev(pkt_dev);
+
+       if (!pkt_dev->odev) {
+               printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n");
+               sprintf(pkt_dev->result,
+                       "ERROR: pkt_dev->odev == NULL in setup_inject.\n");
+               return;
+       }
+
+       /* Default to the interface's mac if not explicitly set. */
 
        if (is_zero_ether_addr(pkt_dev->src_mac))
-              memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN);
+               memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN);
 
-        /* Set up Dest MAC */
+       /* Set up Dest MAC */
        memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
 
-        /* Set up pkt size */
-        pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;
-       
-       if(pkt_dev->flags & F_IPV6) {
+       /* Set up pkt size */
+       pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;
+
+       if (pkt_dev->flags & F_IPV6) {
                /*
                 * Skip this automatic address setting until locks or functions 
                 * gets exported
                 */
 
 #ifdef NOTNOW
-               int i, set = 0, err=1;
+               int i, set = 0, err = 1;
                struct inet6_dev *idev;
 
-               for(i=0; i< IN6_ADDR_HSIZE; i++)
-                       if(pkt_dev->cur_in6_saddr.s6_addr[i]) {
+               for (i = 0; i < IN6_ADDR_HSIZE; i++)
+                       if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
                                set = 1;
                                break;
                        }
 
-               if(!set) {
-                       
+               if (!set) {
+
                        /*
                         * Use linklevel address if unconfigured.
                         *
                         * use ipv6_get_lladdr if/when it's get exported
                         */
 
-
                        read_lock(&addrconf_lock);
                        if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) {
                                struct inet6_ifaddr *ifp;
 
                                read_lock_bh(&idev->lock);
-                               for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
-                                       if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
-                                               ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &ifp->addr);
+                               for (ifp = idev->addr_list; ifp;
+                                    ifp = ifp->if_next) {
+                                       if (ifp->scope == IFA_LINK
+                                           && !(ifp->
+                                                flags & IFA_F_TENTATIVE)) {
+                                               ipv6_addr_copy(&pkt_dev->
+                                                              cur_in6_saddr,
+                                                              &ifp->addr);
                                                err = 0;
                                                break;
                                        }
@@ -1603,28 +1712,28 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
                                read_unlock_bh(&idev->lock);
                        }
                        read_unlock(&addrconf_lock);
-                       if(err) printk("pktgen: ERROR: IPv6 link address not availble.\n");
+                       if (err)
+                               printk("pktgen: ERROR: IPv6 link address not availble.\n");
                }
 #endif
-       } 
-       else {
+       } else {
                pkt_dev->saddr_min = 0;
                pkt_dev->saddr_max = 0;
                if (strlen(pkt_dev->src_min) == 0) {
-                       
-                       struct in_device *in_dev; 
+
+                       struct in_device *in_dev;
 
                        rcu_read_lock();
                        in_dev = __in_dev_get_rcu(pkt_dev->odev);
                        if (in_dev) {
                                if (in_dev->ifa_list) {
-                                       pkt_dev->saddr_min = in_dev->ifa_list->ifa_address;
+                                       pkt_dev->saddr_min =
+                                           in_dev->ifa_list->ifa_address;
                                        pkt_dev->saddr_max = pkt_dev->saddr_min;
                                }
                        }
                        rcu_read_unlock();
-               }
-               else {
+               } else {
                        pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
                        pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
                }
@@ -1632,13 +1741,13 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
                pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
                pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
        }
-        /* Initialize current values. */
-        pkt_dev->cur_dst_mac_offset = 0;
-        pkt_dev->cur_src_mac_offset = 0;
-        pkt_dev->cur_saddr = pkt_dev->saddr_min;
-        pkt_dev->cur_daddr = pkt_dev->daddr_min;
-        pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
-        pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
+       /* Initialize current values. */
+       pkt_dev->cur_dst_mac_offset = 0;
+       pkt_dev->cur_src_mac_offset = 0;
+       pkt_dev->cur_saddr = pkt_dev->saddr_min;
+       pkt_dev->cur_daddr = pkt_dev->daddr_min;
+       pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
+       pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
        pkt_dev->nflows = 0;
 }
 
@@ -1651,7 +1760,7 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
        printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now));
        while (now < spin_until_us) {
                /* TODO: optimize sleeping behavior */
-               if (spin_until_us - now > jiffies_to_usecs(1)+1)
+               if (spin_until_us - now > jiffies_to_usecs(1) + 1)
                        schedule_timeout_interruptible(1);
                else if (spin_until_us - now > 100) {
                        do_softirq();
@@ -1667,102 +1776,110 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
        pkt_dev->idle_acc += now - start;
 }
 
-
 /* Increment/randomize headers according to flags and current values
  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
  */
-static void mod_cur_headers(struct pktgen_dev *pkt_dev) {        
-        __u32 imn;
-        __u32 imx;
-       int  flow = 0;
+static void mod_cur_headers(struct pktgen_dev *pkt_dev)
+{
+       __u32 imn;
+       __u32 imx;
+       int flow = 0;
 
-       if(pkt_dev->cflows)  {
+       if (pkt_dev->cflows) {
                flow = pktgen_random() % pkt_dev->cflows;
-               
+
                if (pkt_dev->flows[flow].count > pkt_dev->lflow)
                        pkt_dev->flows[flow].count = 0;
-       }                                               
-
+       }
 
        /*  Deal with source MAC */
-        if (pkt_dev->src_mac_count > 1) {
-                __u32 mc;
-                __u32 tmp;
-
-                if (pkt_dev->flags & F_MACSRC_RND) 
-                        mc = pktgen_random() % (pkt_dev->src_mac_count);
-                else {
-                        mc = pkt_dev->cur_src_mac_offset++;
-                        if (pkt_dev->cur_src_mac_offset > pkt_dev->src_mac_count) 
-                                pkt_dev->cur_src_mac_offset = 0;
-                }
-
-                tmp = pkt_dev->src_mac[5] + (mc & 0xFF);
-                pkt_dev->hh[11] = tmp;
-                tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
-                pkt_dev->hh[10] = tmp;
-                tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
-                pkt_dev->hh[9] = tmp;
-                tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
-                pkt_dev->hh[8] = tmp;
-                tmp = (pkt_dev->src_mac[1] + (tmp >> 8));
-                pkt_dev->hh[7] = tmp;        
-        }
-
-        /*  Deal with Destination MAC */
-        if (pkt_dev->dst_mac_count > 1) {
-                __u32 mc;
-                __u32 tmp;
-
-                if (pkt_dev->flags & F_MACDST_RND) 
-                        mc = pktgen_random() % (pkt_dev->dst_mac_count);
-
-                else {
-                        mc = pkt_dev->cur_dst_mac_offset++;
-                        if (pkt_dev->cur_dst_mac_offset > pkt_dev->dst_mac_count) {
-                                pkt_dev->cur_dst_mac_offset = 0;
-                        }
-                }
-
-                tmp = pkt_dev->dst_mac[5] + (mc & 0xFF);
-                pkt_dev->hh[5] = tmp;
-                tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
-                pkt_dev->hh[4] = tmp;
-                tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
-                pkt_dev->hh[3] = tmp;
-                tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
-                pkt_dev->hh[2] = tmp;
-                tmp = (pkt_dev->dst_mac[1] + (tmp >> 8));
-                pkt_dev->hh[1] = tmp;        
-        }
-
-        if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
-                if (pkt_dev->flags & F_UDPSRC_RND) 
-                        pkt_dev->cur_udp_src = ((pktgen_random() % (pkt_dev->udp_src_max - pkt_dev->udp_src_min)) + pkt_dev->udp_src_min);
-
-                else {
+       if (pkt_dev->src_mac_count > 1) {
+               __u32 mc;
+               __u32 tmp;
+
+               if (pkt_dev->flags & F_MACSRC_RND)
+                       mc = pktgen_random() % (pkt_dev->src_mac_count);
+               else {
+                       mc = pkt_dev->cur_src_mac_offset++;
+                       if (pkt_dev->cur_src_mac_offset >
+                           pkt_dev->src_mac_count)
+                               pkt_dev->cur_src_mac_offset = 0;
+               }
+
+               tmp = pkt_dev->src_mac[5] + (mc & 0xFF);
+               pkt_dev->hh[11] = tmp;
+               tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
+               pkt_dev->hh[10] = tmp;
+               tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
+               pkt_dev->hh[9] = tmp;
+               tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
+               pkt_dev->hh[8] = tmp;
+               tmp = (pkt_dev->src_mac[1] + (tmp >> 8));
+               pkt_dev->hh[7] = tmp;
+       }
+
+       /*  Deal with Destination MAC */
+       if (pkt_dev->dst_mac_count > 1) {
+               __u32 mc;
+               __u32 tmp;
+
+               if (pkt_dev->flags & F_MACDST_RND)
+                       mc = pktgen_random() % (pkt_dev->dst_mac_count);
+
+               else {
+                       mc = pkt_dev->cur_dst_mac_offset++;
+                       if (pkt_dev->cur_dst_mac_offset >
+                           pkt_dev->dst_mac_count) {
+                               pkt_dev->cur_dst_mac_offset = 0;
+                       }
+               }
+
+               tmp = pkt_dev->dst_mac[5] + (mc & 0xFF);
+               pkt_dev->hh[5] = tmp;
+               tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
+               pkt_dev->hh[4] = tmp;
+               tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
+               pkt_dev->hh[3] = tmp;
+               tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
+               pkt_dev->hh[2] = tmp;
+               tmp = (pkt_dev->dst_mac[1] + (tmp >> 8));
+               pkt_dev->hh[1] = tmp;
+       }
+
+       if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
+               if (pkt_dev->flags & F_UDPSRC_RND)
+                       pkt_dev->cur_udp_src =
+                           ((pktgen_random() %
+                             (pkt_dev->udp_src_max - pkt_dev->udp_src_min)) +
+                            pkt_dev->udp_src_min);
+
+               else {
                        pkt_dev->cur_udp_src++;
                        if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max)
                                pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
-                }
-        }
-
-        if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
-                if (pkt_dev->flags & F_UDPDST_RND) {
-                        pkt_dev->cur_udp_dst = ((pktgen_random() % (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)) + pkt_dev->udp_dst_min);
-                }
-                else {
+               }
+       }
+
+       if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
+               if (pkt_dev->flags & F_UDPDST_RND) {
+                       pkt_dev->cur_udp_dst =
+                           ((pktgen_random() %
+                             (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)) +
+                            pkt_dev->udp_dst_min);
+               } else {
                        pkt_dev->cur_udp_dst++;
-                       if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 
+                       if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
                                pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
-                }
-        }
+               }
+       }
 
        if (!(pkt_dev->flags & F_IPV6)) {
 
-               if ((imn = ntohl(pkt_dev->saddr_min)) < (imx = ntohl(pkt_dev->saddr_max))) {
+               if ((imn = ntohl(pkt_dev->saddr_min)) < (imx =
+                                                        ntohl(pkt_dev->
+                                                              saddr_max))) {
                        __u32 t;
-                       if (pkt_dev->flags & F_IPSRC_RND) 
+                       if (pkt_dev->flags & F_IPSRC_RND)
                                t = ((pktgen_random() % (imx - imn)) + imn);
                        else {
                                t = ntohl(pkt_dev->cur_saddr);
@@ -1773,25 +1890,32 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) {
                        }
                        pkt_dev->cur_saddr = htonl(t);
                }
-               
+
                if (pkt_dev->cflows && pkt_dev->flows[flow].count != 0) {
                        pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
                } else {
 
-                       if ((imn = ntohl(pkt_dev->daddr_min)) < (imx = ntohl(pkt_dev->daddr_max))) {
+                       if ((imn = ntohl(pkt_dev->daddr_min)) < (imx =
+                                                                ntohl(pkt_dev->
+                                                                      daddr_max)))
+                       {
                                __u32 t;
                                if (pkt_dev->flags & F_IPDST_RND) {
 
-                                       t = ((pktgen_random() % (imx - imn)) + imn);
+                                       t = ((pktgen_random() % (imx - imn)) +
+                                            imn);
                                        t = htonl(t);
 
-                                       while( LOOPBACK(t) || MULTICAST(t) || BADCLASS(t) || ZERONET(t) ||  LOCAL_MCAST(t) ) {
-                                               t = ((pktgen_random() % (imx - imn)) + imn);
+                                       while (LOOPBACK(t) || MULTICAST(t)
+                                              || BADCLASS(t) || ZERONET(t)
+                                              || LOCAL_MCAST(t)) {
+                                               t = ((pktgen_random() %
+                                                     (imx - imn)) + imn);
                                                t = htonl(t);
                                        }
                                        pkt_dev->cur_daddr = t;
                                }
-                               
+
                                else {
                                        t = ntohl(pkt_dev->cur_daddr);
                                        t++;
@@ -1801,60 +1925,59 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) {
                                        pkt_dev->cur_daddr = htonl(t);
                                }
                        }
-                       if(pkt_dev->cflows) {   
-                               pkt_dev->flows[flow].cur_daddr = pkt_dev->cur_daddr;
+                       if (pkt_dev->cflows) {
+                               pkt_dev->flows[flow].cur_daddr =
+                                   pkt_dev->cur_daddr;
                                pkt_dev->nflows++;
                        }
                }
-       }
-       else /* IPV6 * */
-       {
-               if(pkt_dev->min_in6_daddr.s6_addr32[0] == 0 &&
-                  pkt_dev->min_in6_daddr.s6_addr32[1] == 0 &&
-                  pkt_dev->min_in6_daddr.s6_addr32[2] == 0 &&
-                  pkt_dev->min_in6_daddr.s6_addr32[3] == 0);
+       } else {                /* IPV6 * */
+
+               if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 &&
+                   pkt_dev->min_in6_daddr.s6_addr32[1] == 0 &&
+                   pkt_dev->min_in6_daddr.s6_addr32[2] == 0 &&
+                   pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ;
                else {
                        int i;
 
                        /* Only random destinations yet */
 
-                       for(i=0; i < 4; i++) {
+                       for (i = 0; i < 4; i++) {
                                pkt_dev->cur_in6_daddr.s6_addr32[i] =
-                                       ((pktgen_random() |
-                                         pkt_dev->min_in6_daddr.s6_addr32[i]) &
-                                        pkt_dev->max_in6_daddr.s6_addr32[i]);
+                                   ((pktgen_random() |
+                                     pkt_dev->min_in6_daddr.s6_addr32[i]) &
+                                    pkt_dev->max_in6_daddr.s6_addr32[i]);
                        }
-               }
+               }
        }
 
-        if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
-                __u32 t;
-                if (pkt_dev->flags & F_TXSIZE_RND) {
-                        t = ((pktgen_random() % (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size))
-                             + pkt_dev->min_pkt_size);
-                }
-                else {
+       if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
+               __u32 t;
+               if (pkt_dev->flags & F_TXSIZE_RND) {
+                       t = ((pktgen_random() %
+                             (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size))
+                            + pkt_dev->min_pkt_size);
+               } else {
                        t = pkt_dev->cur_pkt_size + 1;
-                       if (t > pkt_dev->max_pkt_size) 
+                       if (t > pkt_dev->max_pkt_size)
                                t = pkt_dev->min_pkt_size;
-                }
-                pkt_dev->cur_pkt_size = t;
-        }
+               }
+               pkt_dev->cur_pkt_size = t;
+       }
 
        pkt_dev->flows[flow].count++;
 }
 
-
-static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 
-                                  struct pktgen_dev *pkt_dev)
+static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
+                                       struct pktgen_dev *pkt_dev)
 {
        struct sk_buff *skb = NULL;
        __u8 *eth;
        struct udphdr *udph;
        int datalen, iplen;
        struct iphdr *iph;
-        struct pktgen_hdr *pgh = NULL;
-        
+       struct pktgen_hdr *pgh = NULL;
+
        /* Update any of the values, used when we're incrementing various
         * fields.
         */
@@ -1875,47 +1998,47 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
        memcpy(eth, pkt_dev->hh, 12);
-       *(u16*)&eth[12] = __constant_htons(ETH_P_IP);
+       *(u16 *) & eth[12] = __constant_htons(ETH_P_IP);
 
-       datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
-       if (datalen < sizeof(struct pktgen_hdr)) 
+       datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8;  /* Eth + IPh + UDPh */
+       if (datalen < sizeof(struct pktgen_hdr))
                datalen = sizeof(struct pktgen_hdr);
-        
+
        udph->source = htons(pkt_dev->cur_udp_src);
        udph->dest = htons(pkt_dev->cur_udp_dst);
-       udph->len = htons(datalen + 8); /* DATA + udphdr */
-       udph->check = 0;  /* No checksum */
+       udph->len = htons(datalen + 8); /* DATA + udphdr */
+       udph->check = 0;        /* No checksum */
 
        iph->ihl = 5;
        iph->version = 4;
        iph->ttl = 32;
        iph->tos = 0;
-       iph->protocol = IPPROTO_UDP; /* UDP */
+       iph->protocol = IPPROTO_UDP;    /* UDP */
        iph->saddr = pkt_dev->cur_saddr;
        iph->daddr = pkt_dev->cur_daddr;
        iph->frag_off = 0;
        iplen = 20 + 8 + datalen;
        iph->tot_len = htons(iplen);
        iph->check = 0;
-       iph->check = ip_fast_csum((void *) iph, iph->ihl);
+       iph->check = ip_fast_csum((void *)iph, iph->ihl);
        skb->protocol = __constant_htons(ETH_P_IP);
-       skb->mac.raw = ((u8 *)iph) - 14;
+       skb->mac.raw = ((u8 *) iph) - 14;
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
 
-       if (pkt_dev->nfrags <= 0) 
-                pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
+       if (pkt_dev->nfrags <= 0)
+               pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
        else {
                int frags = pkt_dev->nfrags;
                int i;
 
-                pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
-                
+               pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
+
                if (frags > MAX_SKB_FRAGS)
                        frags = MAX_SKB_FRAGS;
-               if (datalen > frags*PAGE_SIZE) {
-                       skb_put(skb, datalen-frags*PAGE_SIZE);
-                       datalen = frags*PAGE_SIZE;
+               if (datalen > frags * PAGE_SIZE) {
+                       skb_put(skb, datalen - frags * PAGE_SIZE);
+                       datalen = frags * PAGE_SIZE;
                }
 
                i = 0;
@@ -1924,7 +2047,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                        skb_shinfo(skb)->frags[i].page = page;
                        skb_shinfo(skb)->frags[i].page_offset = 0;
                        skb_shinfo(skb)->frags[i].size =
-                               (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+                           (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
                        datalen -= skb_shinfo(skb)->frags[i].size;
                        skb->len += skb_shinfo(skb)->frags[i].size;
                        skb->data_len += skb_shinfo(skb)->frags[i].size;
@@ -1944,30 +2067,33 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
 
                        skb_shinfo(skb)->frags[i - 1].size -= rem;
 
-                       skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1];
+                       skb_shinfo(skb)->frags[i] =
+                           skb_shinfo(skb)->frags[i - 1];
                        get_page(skb_shinfo(skb)->frags[i].page);
-                       skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page;
-                       skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size;
+                       skb_shinfo(skb)->frags[i].page =
+                           skb_shinfo(skb)->frags[i - 1].page;
+                       skb_shinfo(skb)->frags[i].page_offset +=
+                           skb_shinfo(skb)->frags[i - 1].size;
                        skb_shinfo(skb)->frags[i].size = rem;
                        i++;
                        skb_shinfo(skb)->nr_frags = i;
                }
        }
 
-        /* Stamp the time, and sequence number, convert them to network byte order */
+       /* Stamp the time, and sequence number, convert them to network byte order */
+
+       if (pgh) {
+               struct timeval timestamp;
+
+               pgh->pgh_magic = htonl(PKTGEN_MAGIC);
+               pgh->seq_num = htonl(pkt_dev->seq_num);
+
+               do_gettimeofday(&timestamp);
+               pgh->tv_sec = htonl(timestamp.tv_sec);
+               pgh->tv_usec = htonl(timestamp.tv_usec);
+       }
+       pkt_dev->seq_num++;
 
-        if (pgh) {
-              struct timeval timestamp;
-             
-             pgh->pgh_magic = htonl(PKTGEN_MAGIC);
-             pgh->seq_num   = htonl(pkt_dev->seq_num);
-             
-             do_gettimeofday(&timestamp);
-             pgh->tv_sec    = htonl(timestamp.tv_sec);
-             pgh->tv_usec   = htonl(timestamp.tv_usec);
-        }
-        pkt_dev->seq_num++;
-        
        return skb;
 }
 
@@ -1980,23 +2106,24 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
  * --ro
  */
 
-static unsigned int scan_ip6(const char *s,char ip[16])
+static unsigned int scan_ip6(const char *s, char ip[16])
 {
        unsigned int i;
-       unsigned int len=0;
+       unsigned int len = 0;
        unsigned long u;
        char suffix[16];
-       unsigned int prefixlen=0;
-       unsigned int suffixlen=0;
+       unsigned int prefixlen = 0;
+       unsigned int suffixlen = 0;
        __u32 tmp;
 
-       for (i=0; i<16; i++) ip[i]=0;
+       for (i = 0; i < 16; i++)
+               ip[i] = 0;
 
        for (;;) {
                if (*s == ':') {
                        len++;
-                       if (s[1] == ':') {        /* Found "::", skip to part 2 */
-                               s+=2;
+                       if (s[1] == ':') {      /* Found "::", skip to part 2 */
+                               s += 2;
                                len++;
                                break;
                        }
@@ -2004,129 +2131,149 @@ static unsigned int scan_ip6(const char *s,char ip[16])
                }
                {
                        char *tmp;
-                       u=simple_strtoul(s,&tmp,16);
-                       i=tmp-s;
+                       u = simple_strtoul(s, &tmp, 16);
+                       i = tmp - s;
                }
 
-               if (!i) return 0;
-               if (prefixlen==12 && s[i]=='.') {
+               if (!i)
+                       return 0;
+               if (prefixlen == 12 && s[i] == '.') {
 
                        /* the last 4 bytes may be written as IPv4 address */
 
                        tmp = in_aton(s);
-                       memcpy((struct in_addr*)(ip+12), &tmp, sizeof(tmp));
-                       return i+len;
+                       memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp));
+                       return i + len;
                }
                ip[prefixlen++] = (u >> 8);
                ip[prefixlen++] = (u & 255);
-               s += i; len += i;
-               if (prefixlen==16)
+               s += i;
+               len += i;
+               if (prefixlen == 16)
                        return len;
        }
 
 /* part 2, after "::" */
        for (;;) {
                if (*s == ':') {
-                       if (suffixlen==0)
+                       if (suffixlen == 0)
                                break;
                        s++;
                        len++;
-               } else if (suffixlen!=0)
+               } else if (suffixlen != 0)
                        break;
                {
                        char *tmp;
-                       u=simple_strtol(s,&tmp,16);
-                       i=tmp-s;
+                       u = simple_strtol(s, &tmp, 16);
+                       i = tmp - s;
                }
                if (!i) {
-                       if (*s) len--;
+                       if (*s)
+                               len--;
                        break;
                }
-               if (suffixlen+prefixlen<=12 && s[i]=='.') {
+               if (suffixlen + prefixlen <= 12 && s[i] == '.') {
                        tmp = in_aton(s);
-                       memcpy((struct in_addr*)(suffix+suffixlen), &tmp, sizeof(tmp));
-                       suffixlen+=4;
-                       len+=strlen(s);
+                       memcpy((struct in_addr *)(suffix + suffixlen), &tmp,
+                              sizeof(tmp));
+                       suffixlen += 4;
+                       len += strlen(s);
                        break;
                }
                suffix[suffixlen++] = (u >> 8);
                suffix[suffixlen++] = (u & 255);
-               s += i; len += i;
-               if (prefixlen+suffixlen==16)
+               s += i;
+               len += i;
+               if (prefixlen + suffixlen == 16)
                        break;
        }
-       for (i=0; i<suffixlen; i++)
-               ip[16-suffixlen+i] = suffix[i];
+       for (i = 0; i < suffixlen; i++)
+               ip[16 - suffixlen + i] = suffix[i];
        return len;
 }
 
-static char tohex(char hexdigit) {
-       return hexdigit>9?hexdigit+'a'-10:hexdigit+'0';
+static char tohex(char hexdigit)
+{
+       return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
 }
 
-static int fmt_xlong(char* s,unsigned int i) {
-       char* bak=s;
-       *s=tohex((i>>12)&0xf); if (s!=bak || *s!='0') ++s;
-       *s=tohex((i>>8)&0xf); if (s!=bak || *s!='0') ++s;
-       *s=tohex((i>>4)&0xf); if (s!=bak || *s!='0') ++s;
-       *s=tohex(i&0xf);
-       return s-bak+1;
+static int fmt_xlong(char *s, unsigned int i)
+{
+       char *bak = s;
+       *s = tohex((i >> 12) & 0xf);
+       if (s != bak || *s != '0')
+               ++s;
+       *s = tohex((i >> 8) & 0xf);
+       if (s != bak || *s != '0')
+               ++s;
+       *s = tohex((i >> 4) & 0xf);
+       if (s != bak || *s != '0')
+               ++s;
+       *s = tohex(i & 0xf);
+       return s - bak + 1;
 }
 
-static unsigned int fmt_ip6(char *s,const char ip[16]) {
+static unsigned int fmt_ip6(char *s, const char ip[16])
+{
        unsigned int len;
        unsigned int i;
        unsigned int temp;
        unsigned int compressing;
        int j;
 
-       len = 0; compressing = 0;
-       for (j=0; j<16; j+=2) {
+       len = 0;
+       compressing = 0;
+       for (j = 0; j < 16; j += 2) {
 
 #ifdef V4MAPPEDPREFIX
-               if (j==12 && !memcmp(ip,V4mappedprefix,12)) {
-                       inet_ntoa_r(*(struct in_addr*)(ip+12),s);
-                       temp=strlen(s);
-                       return len+temp;
+               if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) {
+                       inet_ntoa_r(*(struct in_addr *)(ip + 12), s);
+                       temp = strlen(s);
+                       return len + temp;
                }
 #endif
-               temp = ((unsigned long) (unsigned char) ip[j] << 8) +
-                       (unsigned long) (unsigned char) ip[j+1];
+               temp = ((unsigned long)(unsigned char)ip[j] << 8) +
+                   (unsigned long)(unsigned char)ip[j + 1];
                if (temp == 0) {
                        if (!compressing) {
-                               compressing=1;
-                               if (j==0) {
-                                       *s++=':'; ++len;
+                               compressing = 1;
+                               if (j == 0) {
+                                       *s++ = ':';
+                                       ++len;
                                }
                        }
                } else {
                        if (compressing) {
-                               compressing=0;
-                               *s++=':'; ++len;
+                               compressing = 0;
+                               *s++ = ':';
+                               ++len;
                        }
-                       i = fmt_xlong(s,temp); len += i; s += i;
-                       if (j<14) {
+                       i = fmt_xlong(s, temp);
+                       len += i;
+                       s += i;
+                       if (j < 14) {
                                *s++ = ':';
                                ++len;
                        }
                }
        }
        if (compressing) {
-               *s++=':'; ++len;
+               *s++ = ':';
+               ++len;
        }
-       *s=0;
+       *s = 0;
        return len;
 }
 
-static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 
-                                  struct pktgen_dev *pkt_dev)
+static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
+                                       struct pktgen_dev *pkt_dev)
 {
        struct sk_buff *skb = NULL;
        __u8 *eth;
        struct udphdr *udph;
        int datalen;
        struct ipv6hdr *iph;
-        struct pktgen_hdr *pgh = NULL;
+       struct pktgen_hdr *pgh = NULL;
 
        /* Update any of the values, used when we're incrementing various
         * fields.
@@ -2147,23 +2294,23 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
 
        memcpy(eth, pkt_dev->hh, 12);
-       *(u16*)&eth[12] = __constant_htons(ETH_P_IPV6);
+       *(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6);
 
-       datalen = pkt_dev->cur_pkt_size-14- 
-               sizeof(struct ipv6hdr)-sizeof(struct udphdr); /* Eth + IPh + UDPh */
+       datalen = pkt_dev->cur_pkt_size - 14 - sizeof(struct ipv6hdr) - sizeof(struct udphdr);  /* Eth + IPh + UDPh */
 
-       if (datalen < sizeof(struct pktgen_hdr)) { 
+       if (datalen < sizeof(struct pktgen_hdr)) {
                datalen = sizeof(struct pktgen_hdr);
                if (net_ratelimit())
-                       printk(KERN_INFO "pktgen: increased datalen to %d\n", datalen);
+                       printk(KERN_INFO "pktgen: increased datalen to %d\n",
+                              datalen);
        }
 
        udph->source = htons(pkt_dev->cur_udp_src);
        udph->dest = htons(pkt_dev->cur_udp_dst);
-       udph->len = htons(datalen + sizeof(struct udphdr)); 
-       udph->check = 0;  /* No checksum */
+       udph->len = htons(datalen + sizeof(struct udphdr));
+       udph->check = 0;        /* No checksum */
 
-        *(u32*)iph = __constant_htonl(0x60000000); /* Version + flow */
+       *(u32 *) iph = __constant_htonl(0x60000000);    /* Version + flow */
 
        iph->hop_limit = 32;
 
@@ -2173,24 +2320,24 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
        ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
 
-       skb->mac.raw = ((u8 *)iph) - 14;
+       skb->mac.raw = ((u8 *) iph) - 14;
        skb->protocol = __constant_htons(ETH_P_IPV6);
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
 
-       if (pkt_dev->nfrags <= 0) 
-                pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
+       if (pkt_dev->nfrags <= 0)
+               pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
        else {
                int frags = pkt_dev->nfrags;
                int i;
 
-                pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
-                
+               pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
+
                if (frags > MAX_SKB_FRAGS)
                        frags = MAX_SKB_FRAGS;
-               if (datalen > frags*PAGE_SIZE) {
-                       skb_put(skb, datalen-frags*PAGE_SIZE);
-                       datalen = frags*PAGE_SIZE;
+               if (datalen > frags * PAGE_SIZE) {
+                       skb_put(skb, datalen - frags * PAGE_SIZE);
+                       datalen = frags * PAGE_SIZE;
                }
 
                i = 0;
@@ -2199,7 +2346,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
                        skb_shinfo(skb)->frags[i].page = page;
                        skb_shinfo(skb)->frags[i].page_offset = 0;
                        skb_shinfo(skb)->frags[i].size =
-                               (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+                           (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
                        datalen -= skb_shinfo(skb)->frags[i].size;
                        skb->len += skb_shinfo(skb)->frags[i].size;
                        skb->data_len += skb_shinfo(skb)->frags[i].size;
@@ -2219,305 +2366,333 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
 
                        skb_shinfo(skb)->frags[i - 1].size -= rem;
 
-                       skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1];
+                       skb_shinfo(skb)->frags[i] =
+                           skb_shinfo(skb)->frags[i - 1];
                        get_page(skb_shinfo(skb)->frags[i].page);
-                       skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page;
-                       skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size;
+                       skb_shinfo(skb)->frags[i].page =
+                           skb_shinfo(skb)->frags[i - 1].page;
+                       skb_shinfo(skb)->frags[i].page_offset +=
+                           skb_shinfo(skb)->frags[i - 1].size;
                        skb_shinfo(skb)->frags[i].size = rem;
                        i++;
                        skb_shinfo(skb)->nr_frags = i;
                }
        }
 
-        /* Stamp the time, and sequence number, convert them to network byte order */
+       /* Stamp the time, and sequence number, convert them to network byte order */
        /* should we update cloned packets too ? */
-        if (pgh) {
-              struct timeval timestamp;
-             
-             pgh->pgh_magic = htonl(PKTGEN_MAGIC);
-             pgh->seq_num   = htonl(pkt_dev->seq_num);
-             
-             do_gettimeofday(&timestamp);
-             pgh->tv_sec    = htonl(timestamp.tv_sec);
-             pgh->tv_usec   = htonl(timestamp.tv_usec);
-        }
-        pkt_dev->seq_num++;
-        
+       if (pgh) {
+               struct timeval timestamp;
+
+               pgh->pgh_magic = htonl(PKTGEN_MAGIC);
+               pgh->seq_num = htonl(pkt_dev->seq_num);
+
+               do_gettimeofday(&timestamp);
+               pgh->tv_sec = htonl(timestamp.tv_sec);
+               pgh->tv_usec = htonl(timestamp.tv_usec);
+       }
+       pkt_dev->seq_num++;
+
        return skb;
 }
 
-static inline struct sk_buff *fill_packet(struct net_device *odev, 
-                                  struct pktgen_dev *pkt_dev)
+static inline struct sk_buff *fill_packet(struct net_device *odev,
+                                         struct pktgen_dev *pkt_dev)
 {
-       if(pkt_dev->flags & F_IPV6) 
+       if (pkt_dev->flags & F_IPV6)
                return fill_packet_ipv6(odev, pkt_dev);
        else
                return fill_packet_ipv4(odev, pkt_dev);
 }
 
-static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 
+static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
 {
-        pkt_dev->seq_num = 1;
-        pkt_dev->idle_acc = 0;
+       pkt_dev->seq_num = 1;
+       pkt_dev->idle_acc = 0;
        pkt_dev->sofar = 0;
-        pkt_dev->tx_bytes = 0;
-        pkt_dev->errors = 0;
+       pkt_dev->tx_bytes = 0;
+       pkt_dev->errors = 0;
 }
 
 /* Set up structure for sending pkts, clear counters */
 
 static void pktgen_run(struct pktgen_thread *t)
 {
-        struct pktgen_dev *pkt_dev = NULL;
+       struct pktgen_dev *pkt_dev;
        int started = 0;
 
        PG_DEBUG(printk("pktgen: entering pktgen_run. %p\n", t));
 
        if_lock(t);
-        for (pkt_dev = t->if_list; pkt_dev; pkt_dev = pkt_dev->next ) {
+       list_for_each_entry(pkt_dev, &t->if_list, list) {
 
                /*
                 * setup odev and create initial packet.
                 */
                pktgen_setup_inject(pkt_dev);
 
-               if(pkt_dev->odev) { 
+               if (pkt_dev->odev) {
                        pktgen_clear_counters(pkt_dev);
-                       pkt_dev->running = 1; /* Cranke yeself! */
+                       pkt_dev->running = 1;   /* Cranke yeself! */
                        pkt_dev->skb = NULL;
                        pkt_dev->started_at = getCurUs();
-                       pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */
+                       pkt_dev->next_tx_us = getCurUs();       /* Transmit immediately */
                        pkt_dev->next_tx_ns = 0;
-                       
+
                        strcpy(pkt_dev->result, "Starting");
                        started++;
-               }
-               else 
+               } else
                        strcpy(pkt_dev->result, "Error starting");
        }
        if_unlock(t);
-       if(started) t->control &= ~(T_STOP);
+       if (started)
+               t->control &= ~(T_STOP);
 }
 
 static void pktgen_stop_all_threads_ifs(void)
 {
-        struct pktgen_thread *t = pktgen_threads;
+       struct pktgen_thread *t;
 
-       PG_DEBUG(printk("pktgen: entering pktgen_stop_all_threads.\n"));
+       PG_DEBUG(printk("pktgen: entering pktgen_stop_all_threads_ifs.\n"));
 
-       thread_lock();
-       while(t) {
-               pktgen_stop(t);
-               t = t->next;
-       }
-       thread_unlock();
+       mutex_lock(&pktgen_thread_lock);
+
+       list_for_each_entry(t, &pktgen_threads, th_list)
+               t->control |= T_STOP;
+
+       mutex_unlock(&pktgen_thread_lock);
 }
 
-static int thread_is_running(struct pktgen_thread *t )
+static int thread_is_running(struct pktgen_thread *t)
 {
-        struct pktgen_dev *next;
-        int res = 0;
+       struct pktgen_dev *pkt_dev;
+       int res = 0;
 
-        for(next=t->if_list; next; next=next->next) { 
-               if(next->running) {
+       list_for_each_entry(pkt_dev, &t->if_list, list)
+               if (pkt_dev->running) {
                        res = 1;
                        break;
                }
-        }
-        return res;
+       return res;
 }
 
-static int pktgen_wait_thread_run(struct pktgen_thread *t )
+static int pktgen_wait_thread_run(struct pktgen_thread *t)
 {
-        if_lock(t);
+       if_lock(t);
 
-        while(thread_is_running(t)) {
+       while (thread_is_running(t)) {
 
-                if_unlock(t);
+               if_unlock(t);
 
-               msleep_interruptible(100); 
+               msleep_interruptible(100);
 
-                if (signal_pending(current)) 
-                        goto signal;
-                if_lock(t);
-        }
-        if_unlock(t);
-        return 1;
- signal:
-        return 0;
+               if (signal_pending(current))
+                       goto signal;
+               if_lock(t);
+       }
+       if_unlock(t);
+       return 1;
+signal:
+       return 0;
 }
 
 static int pktgen_wait_all_threads_run(void)
 {
-       struct pktgen_thread *t = pktgen_threads;
+       struct pktgen_thread *t;
        int sig = 1;
-       
-       while (t) {
+
+       mutex_lock(&pktgen_thread_lock);
+
+       list_for_each_entry(t, &pktgen_threads, th_list) {
                sig = pktgen_wait_thread_run(t);
-               if( sig == 0 ) break;
-               thread_lock();
-               t=t->next;
-               thread_unlock();
-       }
-       if(sig == 0) {
-               thread_lock();
-               while (t) {
-                       t->control |= (T_STOP);
-                       t=t->next;
-               }
-               thread_unlock();
+               if (sig == 0)
+                       break;
        }
+
+       if (sig == 0)
+               list_for_each_entry(t, &pktgen_threads, th_list)
+                       t->control |= (T_STOP);
+
+       mutex_unlock(&pktgen_thread_lock);
        return sig;
 }
 
 static void pktgen_run_all_threads(void)
 {
-        struct pktgen_thread *t = pktgen_threads;
+       struct pktgen_thread *t;
 
        PG_DEBUG(printk("pktgen: entering pktgen_run_all_threads.\n"));
 
-       thread_lock();
+       mutex_lock(&pktgen_thread_lock);
 
-       while(t) {
+       list_for_each_entry(t, &pktgen_threads, th_list)
                t->control |= (T_RUN);
-               t = t->next;
-       }
-       thread_unlock();
 
-       schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
-                       
+       mutex_unlock(&pktgen_thread_lock);
+
+       schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
+
        pktgen_wait_all_threads_run();
 }
 
-
 static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
 {
-       __u64 total_us, bps, mbps, pps, idle;
-       char *p = pkt_dev->result;
-
-       total_us = pkt_dev->stopped_at - pkt_dev->started_at;
-
-       idle = pkt_dev->idle_acc;
-
-       p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
-                    (unsigned long long) total_us, 
-                   (unsigned long long)(total_us - idle), 
-                   (unsigned long long) idle,
-                    (unsigned long long) pkt_dev->sofar, 
-                   pkt_dev->cur_pkt_size, nr_frags);
-
-       pps = pkt_dev->sofar * USEC_PER_SEC;
-
-       while ((total_us >> 32) != 0) {
-               pps >>= 1;
-               total_us >>= 1;
-       }
-
-       do_div(pps, total_us);
-       
-       bps = pps * 8 * pkt_dev->cur_pkt_size;
-
-       mbps = bps;
-       do_div(mbps, 1000000);
-       p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
-                    (unsigned long long) pps, 
-                   (unsigned long long) mbps, 
-                   (unsigned long long) bps, 
-                   (unsigned long long) pkt_dev->errors);
+       __u64 total_us, bps, mbps, pps, idle;
+       char *p = pkt_dev->result;
+
+       total_us = pkt_dev->stopped_at - pkt_dev->started_at;
+
+       idle = pkt_dev->idle_acc;
+
+       p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
+                    (unsigned long long)total_us,
+                    (unsigned long long)(total_us - idle),
+                    (unsigned long long)idle,
+                    (unsigned long long)pkt_dev->sofar,
+                    pkt_dev->cur_pkt_size, nr_frags);
+
+       pps = pkt_dev->sofar * USEC_PER_SEC;
+
+       while ((total_us >> 32) != 0) {
+               pps >>= 1;
+               total_us >>= 1;
+       }
+
+       do_div(pps, total_us);
+
+       bps = pps * 8 * pkt_dev->cur_pkt_size;
+
+       mbps = bps;
+       do_div(mbps, 1000000);
+       p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
+                    (unsigned long long)pps,
+                    (unsigned long long)mbps,
+                    (unsigned long long)bps,
+                    (unsigned long long)pkt_dev->errors);
 }
 
 /* Set stopped-at timer, remove from running list, do counters & statistics */
 
-static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 
+static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
 {
-       
-        if (!pkt_dev->running) {
-                printk("pktgen: interface: %s is already stopped\n", pkt_dev->ifname);
-                return -EINVAL;
-        }
+       int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
 
-        pkt_dev->stopped_at = getCurUs();
-        pkt_dev->running = 0;
+       if (!pkt_dev->running) {
+               printk("pktgen: interface: %s is already stopped\n",
+                      pkt_dev->ifname);
+               return -EINVAL;
+       }
 
-       show_results(pkt_dev, skb_shinfo(pkt_dev->skb)->nr_frags);
+       pkt_dev->stopped_at = getCurUs();
+       pkt_dev->running = 0;
 
-       if (pkt_dev->skb) 
-               kfree_skb(pkt_dev->skb);
+       show_results(pkt_dev, nr_frags);
 
-       pkt_dev->skb = NULL;
-       
-        return 0;
+       return 0;
 }
 
-static struct pktgen_dev *next_to_run(struct pktgen_thread *t )
+static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
 {
-       struct pktgen_dev *next, *best = NULL;
-        
+       struct pktgen_dev *pkt_dev, *best = NULL;
+
        if_lock(t);
 
-       for(next=t->if_list; next ; next=next->next) {
-               if(!next->running) continue;
-               if(best == NULL) best=next;
-               else if ( next->next_tx_us < best->next_tx_us) 
-                       best =  next;
+       list_for_each_entry(pkt_dev, &t->if_list, list) {
+               if (!pkt_dev->running)
+                       continue;
+               if (best == NULL)
+                       best = pkt_dev;
+               else if (pkt_dev->next_tx_us < best->next_tx_us)
+                       best = pkt_dev;
        }
        if_unlock(t);
-        return best;
+       return best;
 }
 
-static void pktgen_stop(struct pktgen_thread *t) {
-        struct pktgen_dev *next = NULL;
+static void pktgen_stop(struct pktgen_thread *t)
+{
+       struct pktgen_dev *pkt_dev;
 
-       PG_DEBUG(printk("pktgen: entering pktgen_stop.\n"));
+       PG_DEBUG(printk("pktgen: entering pktgen_stop\n"));
 
-        if_lock(t);
+       if_lock(t);
 
-        for(next=t->if_list; next; next=next->next)
-                pktgen_stop_device(next);
+       list_for_each_entry(pkt_dev, &t->if_list, list) {
+               pktgen_stop_device(pkt_dev);
+               if (pkt_dev->skb)
+                       kfree_skb(pkt_dev->skb);
 
-        if_unlock(t);
+               pkt_dev->skb = NULL;
+       }
+
+       if_unlock(t);
 }
 
-static void pktgen_rem_all_ifs(struct pktgen_thread *t) 
+/*
+ * one of our devices needs to be removed - find it
+ * and remove it
+ */
+static void pktgen_rem_one_if(struct pktgen_thread *t)
 {
-        struct pktgen_dev *cur, *next = NULL;
-        
-        /* Remove all devices, free mem */
-        if_lock(t);
-
-        for(cur=t->if_list; cur; cur=next) { 
-               next = cur->next;
+       struct list_head *q, *n;
+       struct pktgen_dev *cur;
+
+       PG_DEBUG(printk("pktgen: entering pktgen_rem_one_if\n"));
+
+       if_lock(t);
+
+       list_for_each_safe(q, n, &t->if_list) {
+               cur = list_entry(q, struct pktgen_dev, list);
+
+               if (!cur->removal_mark)
+                       continue;
+
+               if (cur->skb)
+                       kfree_skb(cur->skb);
+               cur->skb = NULL;
+
                pktgen_remove_device(t, cur);
+
+               break;
        }
 
-        if_unlock(t);
+       if_unlock(t);
 }
 
-static void pktgen_rem_thread(struct pktgen_thread *t) 
+static void pktgen_rem_all_ifs(struct pktgen_thread *t)
 {
-        /* Remove from the thread list */
+       struct list_head *q, *n;
+       struct pktgen_dev *cur;
 
-       struct pktgen_thread *tmp = pktgen_threads;
+       /* Remove all devices, free mem */
 
-       remove_proc_entry(t->name, pg_proc_dir);
+       PG_DEBUG(printk("pktgen: entering pktgen_rem_all_ifs\n"));
+       if_lock(t);
 
-       thread_lock();
+       list_for_each_safe(q, n, &t->if_list) {
+               cur = list_entry(q, struct pktgen_dev, list);
 
-       if (tmp == t)
-               pktgen_threads = tmp->next;
-       else {
-               while (tmp) {
-                       if (tmp->next == t) {
-                               tmp->next = t->next;
-                               t->next = NULL;
-                               break;
-                       }
-                       tmp = tmp->next;
-               }
+               if (cur->skb)
+                       kfree_skb(cur->skb);
+               cur->skb = NULL;
+
+               pktgen_remove_device(t, cur);
        }
-        thread_unlock();
+
+       if_unlock(t);
+}
+
+static void pktgen_rem_thread(struct pktgen_thread *t)
+{
+       /* Remove from the thread list */
+
+       remove_proc_entry(t->name, pg_proc_dir);
+
+       mutex_lock(&pktgen_thread_lock);
+
+       list_del(&t->th_list);
+
+       mutex_unlock(&pktgen_thread_lock);
 }
 
 static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
@@ -2527,7 +2702,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
        int ret;
 
        odev = pkt_dev->odev;
-       
+
        if (pkt_dev->delay_us || pkt_dev->delay_ns) {
                u64 now;
 
@@ -2544,67 +2719,71 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                        goto out;
                }
        }
-       
+
        if (netif_queue_stopped(odev) || need_resched()) {
                idle_start = getCurUs();
-               
+
                if (!netif_running(odev)) {
                        pktgen_stop_device(pkt_dev);
+                       if (pkt_dev->skb)
+                               kfree_skb(pkt_dev->skb);
+                       pkt_dev->skb = NULL;
                        goto out;
                }
-               if (need_resched()) 
+               if (need_resched())
                        schedule();
-               
+
                pkt_dev->idle_acc += getCurUs() - idle_start;
-               
+
                if (netif_queue_stopped(odev)) {
-                       pkt_dev->next_tx_us = getCurUs(); /* TODO */
+                       pkt_dev->next_tx_us = getCurUs();       /* TODO */
                        pkt_dev->next_tx_ns = 0;
-                       goto out; /* Try the next interface */
+                       goto out;       /* Try the next interface */
                }
        }
-       
+
        if (pkt_dev->last_ok || !pkt_dev->skb) {
-               if ((++pkt_dev->clone_count >= pkt_dev->clone_skb ) || (!pkt_dev->skb)) {
+               if ((++pkt_dev->clone_count >= pkt_dev->clone_skb)
+                   || (!pkt_dev->skb)) {
                        /* build a new pkt */
-                       if (pkt_dev->skb) 
+                       if (pkt_dev->skb)
                                kfree_skb(pkt_dev->skb);
-                       
+
                        pkt_dev->skb = fill_packet(odev, pkt_dev);
                        if (pkt_dev->skb == NULL) {
                                printk("pktgen: ERROR: couldn't allocate skb in fill_packet.\n");
                                schedule();
-                               pkt_dev->clone_count--; /* back out increment, OOM */
+                               pkt_dev->clone_count--; /* back out increment, OOM */
                                goto out;
                        }
                        pkt_dev->allocated_skbs++;
-                       pkt_dev->clone_count = 0; /* reset counter */
+                       pkt_dev->clone_count = 0;       /* reset counter */
                }
        }
-       
+
        spin_lock_bh(&odev->xmit_lock);
        if (!netif_queue_stopped(odev)) {
 
                atomic_inc(&(pkt_dev->skb->users));
-retry_now:
+             retry_now:
                ret = odev->hard_start_xmit(pkt_dev->skb, odev);
                if (likely(ret == NETDEV_TX_OK)) {
-                       pkt_dev->last_ok = 1;    
+                       pkt_dev->last_ok = 1;
                        pkt_dev->sofar++;
                        pkt_dev->seq_num++;
                        pkt_dev->tx_bytes += pkt_dev->cur_pkt_size;
-                       
-               } else if (ret == NETDEV_TX_LOCKED 
+
+               } else if (ret == NETDEV_TX_LOCKED
                           && (odev->features & NETIF_F_LLTX)) {
                        cpu_relax();
                        goto retry_now;
-               } else {  /* Retry it next time */
-                       
+               } else {        /* Retry it next time */
+
                        atomic_dec(&(pkt_dev->skb->users));
-                       
+
                        if (debug && net_ratelimit())
                                printk(KERN_INFO "pktgen: Hard xmit error\n");
-                       
+
                        pkt_dev->errors++;
                        pkt_dev->last_ok = 0;
                }
@@ -2619,16 +2798,16 @@ retry_now:
                        pkt_dev->next_tx_us++;
                        pkt_dev->next_tx_ns -= 1000;
                }
-       } 
+       }
 
-       else {  /* Retry it next time */
-                pkt_dev->last_ok = 0;
-                pkt_dev->next_tx_us = getCurUs(); /* TODO */
+       else {                  /* Retry it next time */
+               pkt_dev->last_ok = 0;
+               pkt_dev->next_tx_us = getCurUs();       /* TODO */
                pkt_dev->next_tx_ns = 0;
-        }
+       }
 
        spin_unlock_bh(&odev->xmit_lock);
-       
+
        /* If pkt_dev->count is zero, then run forever */
        if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
                if (atomic_read(&(pkt_dev->skb->users)) != 1) {
@@ -2641,72 +2820,74 @@ retry_now:
                        }
                        pkt_dev->idle_acc += getCurUs() - idle_start;
                }
-                
+
                /* Done with this */
                pktgen_stop_device(pkt_dev);
-       } 
- out:;
- }
+               if (pkt_dev->skb)
+                       kfree_skb(pkt_dev->skb);
+               pkt_dev->skb = NULL;
+       }
+out:;
+}
 
 /* 
  * Main loop of the thread goes here
  */
 
-static void pktgen_thread_worker(struct pktgen_thread *t) 
+static void pktgen_thread_worker(struct pktgen_thread *t)
 {
        DEFINE_WAIT(wait);
-        struct pktgen_dev *pkt_dev = NULL;
+       struct pktgen_dev *pkt_dev = NULL;
        int cpu = t->cpu;
        sigset_t tmpsig;
        u32 max_before_softirq;
-        u32 tx_since_softirq = 0;
+       u32 tx_since_softirq = 0;
 
        daemonize("pktgen/%d", cpu);
 
-        /* Block all signals except SIGKILL, SIGSTOP and SIGTERM */
+       /* Block all signals except SIGKILL, SIGSTOP and SIGTERM */
 
-        spin_lock_irq(&current->sighand->siglock);
-        tmpsig = current->blocked;
-        siginitsetinv(&current->blocked, 
-                      sigmask(SIGKILL) | 
-                      sigmask(SIGSTOP)| 
-                      sigmask(SIGTERM));
+       spin_lock_irq(&current->sighand->siglock);
+       tmpsig = current->blocked;
+       siginitsetinv(&current->blocked,
+                     sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGTERM));
 
-        recalc_sigpending();
-        spin_unlock_irq(&current->sighand->siglock);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 
        /* Migrate to the right CPU */
        set_cpus_allowed(current, cpumask_of_cpu(cpu));
-        if (smp_processor_id() != cpu)
-                BUG();
+       if (smp_processor_id() != cpu)
+               BUG();
 
        init_waitqueue_head(&t->queue);
 
        t->control &= ~(T_TERMINATE);
        t->control &= ~(T_RUN);
        t->control &= ~(T_STOP);
+       t->control &= ~(T_REMDEVALL);
        t->control &= ~(T_REMDEV);
 
-        t->pid = current->pid;        
+       t->pid = current->pid;
 
-        PG_DEBUG(printk("pktgen: starting pktgen/%d:  pid=%d\n", cpu, current->pid));
+       PG_DEBUG(printk("pktgen: starting pktgen/%d:  pid=%d\n", cpu, current->pid));
 
        max_before_softirq = t->max_before_softirq;
-        
-        __set_current_state(TASK_INTERRUPTIBLE);
-        mb();
 
-        while (1) {
-               
+       __set_current_state(TASK_INTERRUPTIBLE);
+       mb();
+
+       while (1) {
+
                __set_current_state(TASK_RUNNING);
 
                /*
                 * Get next dev to xmit -- if any.
                 */
 
-                pkt_dev = next_to_run(t);
-                
-                if (pkt_dev) {
+               pkt_dev = next_to_run(t);
+
+               if (pkt_dev) {
 
                        pktgen_xmit(pkt_dev);
 
@@ -2724,115 +2905,125 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
                        }
                } else {
                        prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE);
-                       schedule_timeout(HZ/10);
+                       schedule_timeout(HZ / 10);
                        finish_wait(&(t->queue), &wait);
                }
 
-                /* 
+               /*
                 * Back from sleep, either due to the timeout or signal.
                 * We check if we have any "posted" work for us.
                 */
 
-                if (t->control & T_TERMINATE || signal_pending(current)) 
-                        /* we received a request to terminate ourself */
-                        break;
-               
+               if (t->control & T_TERMINATE || signal_pending(current))
+                       /* we received a request to terminate ourself */
+                       break;
 
-               if(t->control & T_STOP) {
+               if (t->control & T_STOP) {
                        pktgen_stop(t);
                        t->control &= ~(T_STOP);
                }
 
-               if(t->control & T_RUN) {
+               if (t->control & T_RUN) {
                        pktgen_run(t);
                        t->control &= ~(T_RUN);
                }
 
-               if(t->control & T_REMDEV) {
+               if (t->control & T_REMDEVALL) {
                        pktgen_rem_all_ifs(t);
+                       t->control &= ~(T_REMDEVALL);
+               }
+
+               if (t->control & T_REMDEV) {
+                       pktgen_rem_one_if(t);
                        t->control &= ~(T_REMDEV);
                }
 
-               if (need_resched()) 
+               if (need_resched())
                        schedule();
-        } 
+       }
+
+       PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name));
+       pktgen_stop(t);
 
-        PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name));
-        pktgen_stop(t);
+       PG_DEBUG(printk("pktgen: %s removing all device\n", t->name));
+       pktgen_rem_all_ifs(t);
 
-        PG_DEBUG(printk("pktgen: %s removing all device\n", t->name));
-        pktgen_rem_all_ifs(t);
+       PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name));
+       pktgen_rem_thread(t);
 
-        PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name));
-        pktgen_rem_thread(t);
+       t->removed = 1;
 }
 
-static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, const char* ifname) 
+static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
+                                         const char *ifname)
 {
-        struct pktgen_dev *pkt_dev = NULL;
-        if_lock(t);
-
-        for(pkt_dev=t->if_list; pkt_dev; pkt_dev = pkt_dev->next ) {
-                if (strncmp(pkt_dev->ifname, ifname, IFNAMSIZ) == 0) {
-                        break;
-                }
-        }
-
-        if_unlock(t);
-       PG_DEBUG(printk("pktgen: find_dev(%s) returning %p\n", ifname,pkt_dev));
-        return pkt_dev;
+       struct pktgen_dev *p, *pkt_dev = NULL;
+       if_lock(t);
+
+       list_for_each_entry(p, &t->if_list, list)
+               if (strncmp(p->ifname, ifname, IFNAMSIZ) == 0) {
+                       pkt_dev = p;
+                       break;
+               }
+
+       if_unlock(t);
+       PG_DEBUG(printk("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev));
+       return pkt_dev;
 }
 
 /* 
  * Adds a dev at front of if_list. 
  */
 
-static int add_dev_to_thread(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) 
+static int add_dev_to_thread(struct pktgen_thread *t,
+                            struct pktgen_dev *pkt_dev)
 {
        int rv = 0;
-       
-        if_lock(t);
-
-        if (pkt_dev->pg_thread) {
-                printk("pktgen: ERROR:  already assigned to a thread.\n");
-                rv = -EBUSY;
-                goto out;
-        }
-       pkt_dev->next =t->if_list; t->if_list=pkt_dev;
-        pkt_dev->pg_thread = t;
+
+       if_lock(t);
+
+       if (pkt_dev->pg_thread) {
+               printk("pktgen: ERROR:  already assigned to a thread.\n");
+               rv = -EBUSY;
+               goto out;
+       }
+
+       list_add(&pkt_dev->list, &t->if_list);
+       pkt_dev->pg_thread = t;
        pkt_dev->running = 0;
 
- out:
-        if_unlock(t);        
-        return rv;
+out:
+       if_unlock(t);
+       return rv;
 }
 
 /* Called under thread lock */
 
-static int pktgen_add_device(struct pktgen_thread *t, const char* ifname) 
+static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 {
-        struct pktgen_dev *pkt_dev;
+       struct pktgen_dev *pkt_dev;
        struct proc_dir_entry *pe;
-       
+
        /* We don't allow a device to be on several threads */
 
        pkt_dev = __pktgen_NN_threads(ifname, FIND);
        if (pkt_dev) {
-                printk("pktgen: ERROR: interface already used.\n");
-                return -EBUSY;
-        }
+               printk("pktgen: ERROR: interface already used.\n");
+               return -EBUSY;
+       }
 
        pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL);
        if (!pkt_dev)
                return -ENOMEM;
 
-       pkt_dev->flows = vmalloc(MAX_CFLOWS*sizeof(struct flow_state));
+       pkt_dev->flows = vmalloc(MAX_CFLOWS * sizeof(struct flow_state));
        if (pkt_dev->flows == NULL) {
                kfree(pkt_dev);
                return -ENOMEM;
        }
-       memset(pkt_dev->flows, 0, MAX_CFLOWS*sizeof(struct flow_state));
+       memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state));
 
+       pkt_dev->removal_mark = 0;
        pkt_dev->min_pkt_size = ETH_ZLEN;
        pkt_dev->max_pkt_size = ETH_ZLEN;
        pkt_dev->nfrags = 0;
@@ -2841,14 +3032,14 @@ static int pktgen_add_device(struct pktgen_thread *t, const char* ifname)
        pkt_dev->delay_ns = pg_delay_d % 1000;
        pkt_dev->count = pg_count_d;
        pkt_dev->sofar = 0;
-       pkt_dev->udp_src_min = 9; /* sink port */
+       pkt_dev->udp_src_min = 9;       /* sink port */
        pkt_dev->udp_src_max = 9;
        pkt_dev->udp_dst_min = 9;
        pkt_dev->udp_dst_max = 9;
 
        strncpy(pkt_dev->ifname, ifname, IFNAMSIZ);
 
-       if (! pktgen_setup_dev(pkt_dev)) {
+       if (!pktgen_setup_dev(pkt_dev)) {
                printk("pktgen: ERROR: pktgen_setup_dev failed.\n");
                if (pkt_dev->flows)
                        vfree(pkt_dev->flows);
@@ -2871,65 +3062,74 @@ static int pktgen_add_device(struct pktgen_thread *t, const char* ifname)
        return add_dev_to_thread(t, pkt_dev);
 }
 
-static struct pktgen_thread * __init pktgen_find_thread(const char* name) 
+static struct pktgen_thread *__init pktgen_find_thread(const char *name)
 {
-        struct pktgen_thread *t = NULL;
+       struct pktgen_thread *t;
 
-       thread_lock();
+       mutex_lock(&pktgen_thread_lock);
 
-        t = pktgen_threads;
-        while (t) {
-                if (strcmp(t->name, name) == 0) 
-                        break;
+       list_for_each_entry(t, &pktgen_threads, th_list)
+               if (strcmp(t->name, name) == 0) {
+                       mutex_unlock(&pktgen_thread_lock);
+                       return t;
+               }
 
-                t = t->next;
-        }
-        thread_unlock();
-        return t;
+       mutex_unlock(&pktgen_thread_lock);
+       return NULL;
 }
 
-static int __init pktgen_create_thread(const char* name, int cpu) 
+static int __init pktgen_create_thread(const char *name, int cpu)
 {
-        struct pktgen_thread *t = NULL;
+       int err;
+       struct pktgen_thread *t = NULL;
        struct proc_dir_entry *pe;
 
-        if (strlen(name) > 31) {
-                printk("pktgen: ERROR:  Thread name cannot be more than 31 characters.\n");
-                return -EINVAL;
-        }
-        
-        if (pktgen_find_thread(name)) {
-                printk("pktgen: ERROR: thread: %s already exists\n", name);
-                return -EINVAL;
-        }
-
-        t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
-        if (!t) {
-                printk("pktgen: ERROR: out of memory, can't create new thread.\n");
-                return -ENOMEM;
-        }
-
-        strcpy(t->name, name);
-        spin_lock_init(&t->if_lock);
+       if (strlen(name) > 31) {
+               printk("pktgen: ERROR:  Thread name cannot be more than 31 characters.\n");
+               return -EINVAL;
+       }
+
+       if (pktgen_find_thread(name)) {
+               printk("pktgen: ERROR: thread: %s already exists\n", name);
+               return -EINVAL;
+       }
+
+       t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
+       if (!t) {
+               printk("pktgen: ERROR: out of memory, can't create new thread.\n");
+               return -ENOMEM;
+       }
+
+       strcpy(t->name, name);
+       spin_lock_init(&t->if_lock);
        t->cpu = cpu;
-        
-        pe = create_proc_entry(t->name, 0600, pg_proc_dir);
-        if (!pe) {
-                printk("pktgen: cannot create %s/%s procfs entry.\n",
+
+       pe = create_proc_entry(t->name, 0600, pg_proc_dir);
+       if (!pe) {
+               printk("pktgen: cannot create %s/%s procfs entry.\n",
                       PG_PROC_DIR, t->name);
-                kfree(t);
-                return -EINVAL;
-        }
+               kfree(t);
+               return -EINVAL;
+       }
 
        pe->proc_fops = &pktgen_thread_fops;
        pe->data = t;
 
-        t->next = pktgen_threads;
-        pktgen_threads = t;
+       INIT_LIST_HEAD(&t->if_list);
 
-       if (kernel_thread((void *) pktgen_thread_worker, (void *) t, 
-                         CLONE_FS | CLONE_FILES | CLONE_SIGHAND) < 0)
+       list_add_tail(&t->th_list, &pktgen_threads);
+
+       t->removed = 0;
+
+       err = kernel_thread((void *)pktgen_thread_worker, (void *)t,
+                         CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+       if (err < 0) {
                printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
+               remove_proc_entry(t->name, pg_proc_dir);
+               list_del(&t->th_list);
+               kfree(t);
+               return err;
+       }
 
        return 0;
 }
@@ -2937,55 +3137,52 @@ static int __init pktgen_create_thread(const char* name, int cpu)
 /* 
  * Removes a device from the thread if_list. 
  */
-static void _rem_dev_from_if_list(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) 
+static void _rem_dev_from_if_list(struct pktgen_thread *t,
+                                 struct pktgen_dev *pkt_dev)
 {
-       struct pktgen_dev *i, *prev = NULL;
-
-       i = t->if_list;
+       struct list_head *q, *n;
+       struct pktgen_dev *p;
 
-       while(i) {
-               if(i == pkt_dev) {
-                       if(prev) prev->next = i->next;
-                       else t->if_list = NULL;
-                       break;
-               }
-               prev = i;
-               i=i->next;
+       list_for_each_safe(q, n, &t->if_list) {
+               p = list_entry(q, struct pktgen_dev, list);
+               if (p == pkt_dev)
+                       list_del(&p->list);
        }
 }
 
-static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) 
+static int pktgen_remove_device(struct pktgen_thread *t,
+                               struct pktgen_dev *pkt_dev)
 {
 
        PG_DEBUG(printk("pktgen: remove_device pkt_dev=%p\n", pkt_dev));
 
-        if (pkt_dev->running) { 
-                printk("pktgen:WARNING: trying to remove a running interface, stopping it now.\n");
-                pktgen_stop_device(pkt_dev);
-        }
-        
-        /* Dis-associate from the interface */
+       if (pkt_dev->running) {
+               printk("pktgen:WARNING: trying to remove a running interface, stopping it now.\n");
+               pktgen_stop_device(pkt_dev);
+       }
+
+       /* Dis-associate from the interface */
 
        if (pkt_dev->odev) {
                dev_put(pkt_dev->odev);
-                pkt_dev->odev = NULL;
-        }
-        
+               pkt_dev->odev = NULL;
+       }
+
        /* And update the thread if_list */
 
        _rem_dev_from_if_list(t, pkt_dev);
 
-        /* Clean up proc file system */
+       /* Clean up proc file system */
 
        remove_proc_entry(pkt_dev->ifname, pg_proc_dir);
 
        if (pkt_dev->flows)
                vfree(pkt_dev->flows);
        kfree(pkt_dev);
-        return 0;
+       return 0;
 }
 
-static int __init pg_init(void) 
+static int __init pg_init(void)
 {
        int cpu;
        struct proc_dir_entry *pe;
@@ -2998,50 +3195,65 @@ static int __init pg_init(void)
        pg_proc_dir->owner = THIS_MODULE;
 
        pe = create_proc_entry(PGCTRL, 0600, pg_proc_dir);
-        if (pe == NULL) {
-               printk("pktgen: ERROR: cannot create %s procfs entry.\n", PGCTRL);
+       if (pe == NULL) {
+               printk("pktgen: ERROR: cannot create %s procfs entry.\n",
+                      PGCTRL);
                proc_net_remove(PG_PROC_DIR);
-                return -EINVAL;
-        }
+               return -EINVAL;
+       }
 
-        pe->proc_fops = &pktgen_fops;
-        pe->data      = NULL;
+       pe->proc_fops = &pktgen_fops;
+       pe->data = NULL;
 
        /* Register us to receive netdevice events */
        register_netdevice_notifier(&pktgen_notifier_block);
-        
+
        for_each_online_cpu(cpu) {
+               int err;
                char buf[30];
 
-                sprintf(buf, "kpktgend_%i", cpu);
-                pktgen_create_thread(buf, cpu);
-        }
-        return 0;        
+               sprintf(buf, "kpktgend_%i", cpu);
+               err = pktgen_create_thread(buf, cpu);
+               if (err)
+                       printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n",
+                                       cpu, err);
+       }
+
+       if (list_empty(&pktgen_threads)) {
+               printk("pktgen: ERROR: Initialization failed for all threads\n");
+               unregister_netdevice_notifier(&pktgen_notifier_block);
+               remove_proc_entry(PGCTRL, pg_proc_dir);
+               proc_net_remove(PG_PROC_DIR);
+               return -ENODEV;
+       }
+
+       return 0;
 }
 
 static void __exit pg_cleanup(void)
 {
+       struct pktgen_thread *t;
+       struct list_head *q, *n;
        wait_queue_head_t queue;
        init_waitqueue_head(&queue);
 
-        /* Stop all interfaces & threads */        
+       /* Stop all interfaces & threads */
 
-        while (pktgen_threads) {
-                struct pktgen_thread *t = pktgen_threads;
-                pktgen_threads->control |= (T_TERMINATE);
+       list_for_each_safe(q, n, &pktgen_threads) {
+               t = list_entry(q, struct pktgen_thread, th_list);
+               t->control |= (T_TERMINATE);
 
-               wait_event_interruptible_timeout(queue, (t != pktgen_threads), HZ);
-        }
+               wait_event_interruptible_timeout(queue, (t->removed == 1), HZ);
+       }
 
-        /* Un-register us from receiving netdevice events */
+       /* Un-register us from receiving netdevice events */
        unregister_netdevice_notifier(&pktgen_notifier_block);
 
-        /* Clean up proc file system */
+       /* Clean up proc file system */
        remove_proc_entry(PGCTRL, pg_proc_dir);
        proc_net_remove(PG_PROC_DIR);
 }
 
-
 module_init(pg_init);
 module_exit(pg_cleanup);
 
index eca2976..ae10d37 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/security.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <net/pkt_sched.h>
 #include <net/netlink.h>
 
-DECLARE_MUTEX(rtnl_sem);
+static DEFINE_MUTEX(rtnl_mutex);
 
 void rtnl_lock(void)
 {
-       rtnl_shlock();
+       mutex_lock(&rtnl_mutex);
 }
 
-int rtnl_lock_interruptible(void)
+void __rtnl_unlock(void)
 {
-       return down_interruptible(&rtnl_sem);
+       mutex_unlock(&rtnl_mutex);
 }
+
 void rtnl_unlock(void)
 {
-       rtnl_shunlock();
-
+       mutex_unlock(&rtnl_mutex);
+       if (rtnl && rtnl->sk_receive_queue.qlen)
+               rtnl->sk_data_ready(rtnl, 0);
        netdev_run_todo();
 }
 
+int rtnl_trylock(void)
+{
+       return mutex_trylock(&rtnl_mutex);
+}
+
 int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
 {
        memset(tb, 0, sizeof(struct rtattr*)*maxattr);
@@ -179,6 +186,33 @@ rtattr_failure:
 }
 
 
+static void set_operstate(struct net_device *dev, unsigned char transition)
+{
+       unsigned char operstate = dev->operstate;
+
+       switch(transition) {
+       case IF_OPER_UP:
+               if ((operstate == IF_OPER_DORMANT ||
+                    operstate == IF_OPER_UNKNOWN) &&
+                   !netif_dormant(dev))
+                       operstate = IF_OPER_UP;
+               break;
+
+       case IF_OPER_DORMANT:
+               if (operstate == IF_OPER_UP ||
+                   operstate == IF_OPER_UNKNOWN)
+                       operstate = IF_OPER_DORMANT;
+               break;
+       };
+
+       if (dev->operstate != operstate) {
+               write_lock_bh(&dev_base_lock);
+               dev->operstate = operstate;
+               write_unlock_bh(&dev_base_lock);
+               netdev_state_change(dev);
+       }
+}
+
 static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                                 int type, u32 pid, u32 seq, u32 change, 
                                 unsigned int flags)
@@ -209,6 +243,13 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        }
 
        if (1) {
+               u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN;
+               u8 link_mode = dev->link_mode;
+               RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate);
+               RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode);
+       }
+
+       if (1) {
                struct rtnl_link_ifmap map = {
                        .mem_start   = dev->mem_start,
                        .mem_end     = dev->mem_end,
@@ -399,6 +440,22 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1]));
        }
 
+       if (ida[IFLA_OPERSTATE - 1]) {
+               if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
+                       goto out;
+
+               set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1])));
+       }
+
+       if (ida[IFLA_LINKMODE - 1]) {
+               if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
+                       goto out;
+
+               write_lock_bh(&dev_base_lock);
+               dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1]));
+               write_unlock_bh(&dev_base_lock);
+       }
+
        if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
                char ifname[IFNAMSIZ];
 
@@ -575,9 +632,9 @@ static void rtnetlink_rcv(struct sock *sk, int len)
        unsigned int qlen = 0;
 
        do {
-               rtnl_lock();
+               mutex_lock(&rtnl_mutex);
                netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg);
-               up(&rtnl_sem);
+               mutex_unlock(&rtnl_mutex);
 
                netdev_run_todo();
        } while (qlen);
@@ -654,6 +711,5 @@ EXPORT_SYMBOL(rtnetlink_links);
 EXPORT_SYMBOL(rtnetlink_put_metrics);
 EXPORT_SYMBOL(rtnl);
 EXPORT_SYMBOL(rtnl_lock);
-EXPORT_SYMBOL(rtnl_lock_interruptible);
-EXPORT_SYMBOL(rtnl_sem);
+EXPORT_SYMBOL(rtnl_trylock);
 EXPORT_SYMBOL(rtnl_unlock);
index 2144952..c9f8784 100644 (file)
@@ -356,6 +356,24 @@ void __kfree_skb(struct sk_buff *skb)
 }
 
 /**
+ *     kfree_skb - free an sk_buff
+ *     @skb: buffer to free
+ *
+ *     Drop a reference to the buffer and free it if the usage count has
+ *     hit zero.
+ */
+void kfree_skb(struct sk_buff *skb)
+{
+       if (unlikely(!skb))
+               return;
+       if (likely(atomic_read(&skb->users) == 1))
+               smp_rmb();
+       else if (likely(!atomic_dec_and_test(&skb->users)))
+               return;
+       __kfree_skb(skb);
+}
+
+/**
  *     skb_clone       -       duplicate an sk_buff
  *     @skb: buffer to clone
  *     @gfp_mask: allocation priority
@@ -1777,6 +1795,29 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
        return 0;
 }
 
+/**
+ *     skb_pull_rcsum - pull skb and update receive checksum
+ *     @skb: buffer to update
+ *     @start: start of data before pull
+ *     @len: length of data pulled
+ *
+ *     This function performs an skb_pull on the packet and updates
+ *     update the CHECKSUM_HW checksum.  It should be used on receive
+ *     path processing instead of skb_pull unless you know that the
+ *     checksum difference is zero (e.g., a valid IP header) or you
+ *     are setting ip_summed to CHECKSUM_NONE.
+ */
+unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
+{
+       BUG_ON(len > skb->len);
+       skb->len -= len;
+       BUG_ON(skb->len < skb->data_len);
+       skb_postpull_rcsum(skb, skb->data, len);
+       return skb->data += len;
+}
+
+EXPORT_SYMBOL_GPL(skb_pull_rcsum);
+
 void __init skb_init(void)
 {
        skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
@@ -1799,6 +1840,7 @@ void __init skb_init(void)
 
 EXPORT_SYMBOL(___pskb_trim);
 EXPORT_SYMBOL(__kfree_skb);
+EXPORT_SYMBOL(kfree_skb);
 EXPORT_SYMBOL(__pskb_pull_tail);
 EXPORT_SYMBOL(__alloc_skb);
 EXPORT_SYMBOL(pskb_copy);
index 6e00811..1a7e6ea 100644 (file)
@@ -616,7 +616,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                        break;
 
                case SO_PEERSEC:
-                       return security_socket_getpeersec(sock, optval, optlen, len);
+                       return security_socket_getpeersec_stream(sock, optval, optlen, len);
 
                default:
                        return(-ENOPROTOOPT);
@@ -1385,6 +1385,20 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname,
 
 EXPORT_SYMBOL(sock_common_getsockopt);
 
+#ifdef CONFIG_COMPAT
+int compat_sock_common_getsockopt(struct socket *sock, int level, int optname,
+                                 char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+
+       if (sk->sk_prot->compat_setsockopt != NULL)
+               return sk->sk_prot->compat_getsockopt(sk, level, optname,
+                                                     optval, optlen);
+       return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen);
+}
+EXPORT_SYMBOL(compat_sock_common_getsockopt);
+#endif
+
 int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock,
                        struct msghdr *msg, size_t size, int flags)
 {
@@ -1414,6 +1428,20 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname,
 
 EXPORT_SYMBOL(sock_common_setsockopt);
 
+#ifdef CONFIG_COMPAT
+int compat_sock_common_setsockopt(struct socket *sock, int level, int optname,
+                                 char __user *optval, int optlen)
+{
+       struct sock *sk = sock->sk;
+
+       if (sk->sk_prot->compat_setsockopt != NULL)
+               return sk->sk_prot->compat_setsockopt(sk, level, optname,
+                                                     optval, optlen);
+       return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen);
+}
+EXPORT_SYMBOL(compat_sock_common_setsockopt);
+#endif
+
 void sk_common_release(struct sock *sk)
 {
        if (sk->sk_prot->destroy)
index 2f278c8..7104536 100644 (file)
@@ -26,6 +26,11 @@ extern int sysctl_core_destroy_delay;
 extern char sysctl_divert_version[];
 #endif /* CONFIG_NET_DIVERT */
 
+#ifdef CONFIG_XFRM
+extern u32 sysctl_xfrm_aevent_etime;
+extern u32 sysctl_xfrm_aevent_rseqth;
+#endif
+
 ctl_table core_table[] = {
 #ifdef CONFIG_NET
        {
@@ -111,6 +116,24 @@ ctl_table core_table[] = {
                .proc_handler   = &proc_dostring
        },
 #endif /* CONFIG_NET_DIVERT */
+#ifdef CONFIG_XFRM
+       {
+               .ctl_name       = NET_CORE_AEVENT_ETIME,
+               .procname       = "xfrm_aevent_etime",
+               .data           = &sysctl_xfrm_aevent_etime,
+               .maxlen         = sizeof(u32),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+       {
+               .ctl_name       = NET_CORE_AEVENT_RSEQTH,
+               .procname       = "xfrm_aevent_rseqth",
+               .data           = &sysctl_xfrm_aevent_rseqth,
+               .maxlen         = sizeof(u32),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+#endif /* CONFIG_XFRM */
 #endif /* CONFIG_NET */
        {
                .ctl_name       = NET_CORE_SOMAXCONN,
index 187ac18..7e096ba 100644 (file)
@@ -24,6 +24,10 @@ config INET_DCCP_DIAG
        def_tristate y if (IP_DCCP = y && INET_DIAG = y)
        def_tristate m
 
+config IP_DCCP_ACKVEC
+       depends on IP_DCCP
+       def_bool N
+
 source "net/dccp/ccids/Kconfig"
 
 menu "DCCP Kernel Hacking"
@@ -36,15 +40,6 @@ config IP_DCCP_DEBUG
 
          Just say N.
 
-config IP_DCCP_UNLOAD_HACK
-       depends on IP_DCCP=m && IP_DCCP_CCID3=m
-       bool "DCCP control sock unload hack"
-       ---help---
-         Enable this to be able to unload the dccp module when the it
-         has only one refcount held, the control sock one. Just execute
-         "rmmod dccp_ccid3 dccp"
-
-         Just say N.
 endmenu
 
 endmenu
index 87b27ff..7696e21 100644 (file)
@@ -2,15 +2,18 @@ obj-$(CONFIG_IPV6) += dccp_ipv6.o
 
 dccp_ipv6-y := ipv6.o
 
-obj-$(CONFIG_IP_DCCP) += dccp.o
+obj-$(CONFIG_IP_DCCP) += dccp.o dccp_ipv4.o
 
-dccp-y := ccid.o input.o ipv4.o minisocks.o options.o output.o proto.o \
-         timer.o
+dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o
+
+dccp_ipv4-y := ipv4.o
 
 dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o
 
 obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
 
+dccp-$(CONFIG_SYSCTL) += sysctl.o
+
 dccp_diag-y := diag.o
 
 obj-y += ccids/
index 2c77daf..b5981e5 100644 (file)
 #include "dccp.h"
 
 #include <linux/dccp.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/skbuff.h>
+#include <linux/slab.h>
 
 #include <net/sock.h>
 
+static kmem_cache_t *dccp_ackvec_slab;
+static kmem_cache_t *dccp_ackvec_record_slab;
+
+static struct dccp_ackvec_record *dccp_ackvec_record_new(void)
+{
+       struct dccp_ackvec_record *avr =
+                       kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC);
+
+       if (avr != NULL)
+               INIT_LIST_HEAD(&avr->dccpavr_node);
+
+       return avr;
+}
+
+static void dccp_ackvec_record_delete(struct dccp_ackvec_record *avr)
+{
+       if (unlikely(avr == NULL))
+               return;
+       /* Check if deleting a linked record */
+       WARN_ON(!list_empty(&avr->dccpavr_node));
+       kmem_cache_free(dccp_ackvec_record_slab, avr);
+}
+
+static void dccp_ackvec_insert_avr(struct dccp_ackvec *av,
+                                  struct dccp_ackvec_record *avr)
+{
+       /*
+        * AVRs are sorted by seqno. Since we are sending them in order, we
+        * just add the AVR at the head of the list.
+        * -sorbo.
+        */
+       if (!list_empty(&av->dccpav_records)) {
+               const struct dccp_ackvec_record *head =
+                                       list_entry(av->dccpav_records.next,
+                                                  struct dccp_ackvec_record,
+                                                  dccpavr_node);
+               BUG_ON(before48(avr->dccpavr_ack_seqno,
+                               head->dccpavr_ack_seqno));
+       }
+
+       list_add(&avr->dccpavr_node, &av->dccpav_records);
+}
+
 int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
+#ifdef CONFIG_IP_DCCP_DEBUG
+       const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+                               "CLIENT tx: " : "server tx: ";
+#endif
        struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
        int len = av->dccpav_vec_len + 2;
        struct timeval now;
        u32 elapsed_time;
        unsigned char *to, *from;
+       struct dccp_ackvec_record *avr;
+
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+               return -1;
 
        dccp_timestamp(sk, &now);
        elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10;
 
-       if (elapsed_time != 0)
-               dccp_insert_option_elapsed_time(sk, skb, elapsed_time);
-
-       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+       if (elapsed_time != 0 &&
+           dccp_insert_option_elapsed_time(sk, skb, elapsed_time))
                return -1;
 
-       /*
-        * XXX: now we have just one ack vector sent record, so
-        * we have to wait for it to be cleared.
-        *
-        * Of course this is not acceptable, but this is just for
-        * basic testing now.
-        */
-       if (av->dccpav_ack_seqno != DCCP_MAX_SEQNO + 1)
+       avr = dccp_ackvec_record_new();
+       if (avr == NULL)
                return -1;
 
        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
@@ -55,8 +102,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
        from = av->dccpav_buf + av->dccpav_buf_head;
 
        /* Check if buf_head wraps */
-       if ((int)av->dccpav_buf_head + len > av->dccpav_vec_len) {
-               const u32 tailsize = av->dccpav_vec_len - av->dccpav_buf_head;
+       if ((int)av->dccpav_buf_head + len > DCCP_MAX_ACKVEC_LEN) {
+               const u32 tailsize = DCCP_MAX_ACKVEC_LEN - av->dccpav_buf_head;
 
                memcpy(to, from, tailsize);
                to   += tailsize;
@@ -73,45 +120,37 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
         *      sequence number it used for the ack packet; ack_ptr will equal
         *      buf_head; ack_ackno will equal buf_ackno; and ack_nonce will
         *      equal buf_nonce.
-        *
-        * This implemention uses just one ack record for now.
         */
-       av->dccpav_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
-       av->dccpav_ack_ptr   = av->dccpav_buf_head;
-       av->dccpav_ack_ackno = av->dccpav_buf_ackno;
-       av->dccpav_ack_nonce = av->dccpav_buf_nonce;
-       av->dccpav_sent_len  = av->dccpav_vec_len;
+       avr->dccpavr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+       avr->dccpavr_ack_ptr   = av->dccpav_buf_head;
+       avr->dccpavr_ack_ackno = av->dccpav_buf_ackno;
+       avr->dccpavr_ack_nonce = av->dccpav_buf_nonce;
+       avr->dccpavr_sent_len  = av->dccpav_vec_len;
+
+       dccp_ackvec_insert_avr(av, avr);
 
        dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, "
                      "ack_ackno=%llu\n",
-                     debug_prefix, av->dccpav_sent_len,
-                     (unsigned long long)av->dccpav_ack_seqno,
-                     (unsigned long long)av->dccpav_ack_ackno);
-       return -1;
+                     debug_prefix, avr->dccpavr_sent_len,
+                     (unsigned long long)avr->dccpavr_ack_seqno,
+                     (unsigned long long)avr->dccpavr_ack_ackno);
+       return 0;
 }
 
-struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len,
-                                     const gfp_t priority)
+struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
 {
-       struct dccp_ackvec *av;
-
-       BUG_ON(len == 0);
+       struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
 
-       if (len > DCCP_MAX_ACKVEC_LEN)
-               return NULL;
-
-       av = kmalloc(sizeof(*av) + len, priority);
        if (av != NULL) {
-               av->dccpav_buf_len      = len;
                av->dccpav_buf_head     =
-                       av->dccpav_buf_tail = av->dccpav_buf_len - 1;
-               av->dccpav_buf_ackno    =
-                       av->dccpav_ack_ackno = av->dccpav_ack_seqno = ~0LLU;
+                       av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
+               av->dccpav_buf_ackno    = DCCP_MAX_SEQNO + 1;
                av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0;
                av->dccpav_ack_ptr      = 0;
                av->dccpav_time.tv_sec  = 0;
                av->dccpav_time.tv_usec = 0;
                av->dccpav_sent_len     = av->dccpav_vec_len = 0;
+               INIT_LIST_HEAD(&av->dccpav_records);
        }
 
        return av;
@@ -119,7 +158,20 @@ struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len,
 
 void dccp_ackvec_free(struct dccp_ackvec *av)
 {
-       kfree(av);
+       if (unlikely(av == NULL))
+               return;
+
+       if (!list_empty(&av->dccpav_records)) {
+               struct dccp_ackvec_record *avr, *next;
+
+               list_for_each_entry_safe(avr, next, &av->dccpav_records,
+                                        dccpavr_node) {
+                       list_del_init(&avr->dccpavr_node);
+                       dccp_ackvec_record_delete(avr);
+               }
+       }
+
+       kmem_cache_free(dccp_ackvec_slab, av);
 }
 
 static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av,
@@ -146,7 +198,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
        unsigned int gap;
        long new_head;
 
-       if (av->dccpav_vec_len + packets > av->dccpav_buf_len)
+       if (av->dccpav_vec_len + packets > DCCP_MAX_ACKVEC_LEN)
                return -ENOBUFS;
 
        gap      = packets - 1;
@@ -158,7 +210,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
                               gap + new_head + 1);
                        gap = -new_head;
                }
-               new_head += av->dccpav_buf_len;
+               new_head += DCCP_MAX_ACKVEC_LEN;
        } 
 
        av->dccpav_buf_head = new_head;
@@ -251,7 +303,7 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
                                goto out_duplicate;
 
                        delta -= len + 1;
-                       if (++index == av->dccpav_buf_len)
+                       if (++index == DCCP_MAX_ACKVEC_LEN)
                                index = 0;
                }
        }
@@ -259,7 +311,6 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
        av->dccpav_buf_ackno = ackno;
        dccp_timestamp(sk, &av->dccpav_time);
 out:
-       dccp_pr_debug("");
        return 0;
 
 out_duplicate:
@@ -297,44 +348,50 @@ void dccp_ackvec_print(const struct dccp_ackvec *av)
 }
 #endif
 
-static void dccp_ackvec_throw_away_ack_record(struct dccp_ackvec *av)
+static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
+                                    struct dccp_ackvec_record *avr)
 {
-       /*
-        * As we're keeping track of the ack vector size (dccpav_vec_len) and
-        * the sent ack vector size (dccpav_sent_len) we don't need
-        * dccpav_buf_tail at all, but keep this code here as in the future
-        * we'll implement a vector of ack records, as suggested in
-        * draft-ietf-dccp-spec-11.txt Appendix A. -acme
-        */
-#if 0
-       u32 new_buf_tail = av->dccpav_ack_ptr + 1;
-       if (new_buf_tail >= av->dccpav_vec_len)
-               new_buf_tail -= av->dccpav_vec_len;
-       av->dccpav_buf_tail = new_buf_tail;
-#endif
-       av->dccpav_vec_len -= av->dccpav_sent_len;
+       struct dccp_ackvec_record *next;
+
+       av->dccpav_buf_tail = avr->dccpavr_ack_ptr - 1;
+       if (av->dccpav_buf_tail == 0)
+               av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
+
+       av->dccpav_vec_len -= avr->dccpavr_sent_len;
+
+       /* free records */
+       list_for_each_entry_safe_from(avr, next, &av->dccpav_records,
+                                     dccpavr_node) {
+               list_del_init(&avr->dccpavr_node);
+               dccp_ackvec_record_delete(avr);
+       }
 }
 
 void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk,
                                 const u64 ackno)
 {
-       /* Check if we actually sent an ACK vector */
-       if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1)
-               return;
+       struct dccp_ackvec_record *avr;
 
-       if (ackno == av->dccpav_ack_seqno) {
+       /*
+        * If we traverse backwards, it should be faster when we have large
+        * windows. We will be receiving ACKs for stuff we sent a while back
+        * -sorbo.
+        */
+       list_for_each_entry_reverse(avr, &av->dccpav_records, dccpavr_node) {
+               if (ackno == avr->dccpavr_ack_seqno) {
 #ifdef CONFIG_IP_DCCP_DEBUG
-               struct dccp_sock *dp = dccp_sk(sk);
-               const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
-                                       "CLIENT rx ack: " : "server rx ack: ";
+                       struct dccp_sock *dp = dccp_sk(sk);
+                       const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+                                               "CLIENT rx ack: " : "server rx ack: ";
 #endif
-               dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, "
-                             "ack_ackno=%llu, ACKED!\n",
-                             debug_prefix, 1,
-                             (unsigned long long)av->dccpav_ack_seqno,
-                             (unsigned long long)av->dccpav_ack_ackno);
-               dccp_ackvec_throw_away_ack_record(av);
-               av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1;
+                       dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, "
+                                     "ack_ackno=%llu, ACKED!\n",
+                                     debug_prefix, 1,
+                                     (unsigned long long)avr->dccpavr_ack_seqno,
+                                     (unsigned long long)avr->dccpavr_ack_ackno);
+                       dccp_ackvec_throw_record(av, avr);
+                       break;
+               }
        }
 }
 
@@ -344,28 +401,20 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
                                            const unsigned char *vector)
 {
        unsigned char i;
+       struct dccp_ackvec_record *avr;
 
        /* Check if we actually sent an ACK vector */
-       if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1)
-               return;
-       /*
-        * We're in the receiver half connection, so if the received an ACK
-        * vector ackno (e.g. 50) before dccpav_ack_seqno (e.g. 52), we're
-        * not interested.
-        *
-        * Extra explanation with example:
-        * 
-        * if we received an ACK vector with ackno 50, it can only be acking
-        * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent).
-        */
-       /* dccp_pr_debug("is %llu < %llu? ", ackno, av->dccpav_ack_seqno); */
-       if (before48(ackno, av->dccpav_ack_seqno)) {
-               /* dccp_pr_debug_cat("yes\n"); */
+       if (list_empty(&av->dccpav_records))
                return;
-       }
-       /* dccp_pr_debug_cat("no\n"); */
 
        i = len;
+       /*
+        * XXX
+        * I think it might be more efficient to work backwards. See comment on
+        * rcv_ackno. -sorbo.
+        */
+       avr = list_entry(av->dccpav_records.next, struct dccp_ackvec_record,
+                        dccpavr_node);
        while (i--) {
                const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
                u64 ackno_end_rl;
@@ -373,14 +422,20 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
                dccp_set_seqno(&ackno_end_rl, ackno - rl);
 
                /*
-                * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl,
-                * av->dccpav_ack_seqno, ackno);
+                * If our AVR sequence number is greater than the ack, go
+                * forward in the AVR list until it is not so.
                 */
-               if (between48(av->dccpav_ack_seqno, ackno_end_rl, ackno)) {
+               list_for_each_entry_from(avr, &av->dccpav_records,
+                                        dccpavr_node) {
+                       if (!after48(avr->dccpavr_ack_seqno, ackno))
+                               goto found;
+               }
+               /* End of the dccpav_records list, not found, exit */
+               break;
+found:
+               if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) {
                        const u8 state = (*vector &
                                          DCCP_ACKVEC_STATE_MASK) >> 6;
-                       /* dccp_pr_debug_cat("yes\n"); */
-
                        if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) {
 #ifdef CONFIG_IP_DCCP_DEBUG
                                struct dccp_sock *dp = dccp_sk(sk);
@@ -393,19 +448,16 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
                                              "ACKED!\n",
                                              debug_prefix, len,
                                              (unsigned long long)
-                                             av->dccpav_ack_seqno,
+                                             avr->dccpavr_ack_seqno,
                                              (unsigned long long)
-                                             av->dccpav_ack_ackno);
-                               dccp_ackvec_throw_away_ack_record(av);
+                                             avr->dccpavr_ack_ackno);
+                               dccp_ackvec_throw_record(av, avr);
                        }
                        /*
-                        * If dccpav_ack_seqno was not received, no problem
-                        * we'll send another ACK vector.
+                        * If it wasn't received, continue scanning... we might
+                        * find another one.
                         */
-                       av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1;
-                       break;
                }
-               /* dccp_pr_debug_cat("no\n"); */
 
                dccp_set_seqno(&ackno, ackno_end_rl - 1);
                ++vector;
@@ -424,3 +476,43 @@ int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
                                        len, value);
        return 0;
 }
+
+static char dccp_ackvec_slab_msg[] __initdata =
+       KERN_CRIT "DCCP: Unable to create ack vectors slab caches\n";
+
+int __init dccp_ackvec_init(void)
+{
+       dccp_ackvec_slab = kmem_cache_create("dccp_ackvec",
+                                            sizeof(struct dccp_ackvec), 0,
+                                            SLAB_HWCACHE_ALIGN, NULL, NULL);
+       if (dccp_ackvec_slab == NULL)
+               goto out_err;
+
+       dccp_ackvec_record_slab =
+                       kmem_cache_create("dccp_ackvec_record",
+                                         sizeof(struct dccp_ackvec_record),
+                                         0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+       if (dccp_ackvec_record_slab == NULL)
+               goto out_destroy_slab;
+
+       return 0;
+
+out_destroy_slab:
+       kmem_cache_destroy(dccp_ackvec_slab);
+       dccp_ackvec_slab = NULL;
+out_err:
+       printk(dccp_ackvec_slab_msg);
+       return -ENOBUFS;
+}
+
+void dccp_ackvec_exit(void)
+{
+       if (dccp_ackvec_slab != NULL) {
+               kmem_cache_destroy(dccp_ackvec_slab);
+               dccp_ackvec_slab = NULL;
+       }
+       if (dccp_ackvec_record_slab != NULL) {
+               kmem_cache_destroy(dccp_ackvec_record_slab);
+               dccp_ackvec_record_slab = NULL;
+       }
+}
index f7dfb5f..ec7a89b 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/config.h>
 #include <linux/compiler.h>
+#include <linux/list.h>
 #include <linux/time.h>
 #include <linux/types.h>
 
  * Ack Vectors it has recently sent. For each packet sent carrying an
  * Ack Vector, it remembers four variables:
  *
- * @dccpav_ack_seqno - the Sequence Number used for the packet
- *                    (HC-Receiver seqno)
  * @dccpav_ack_ptr - the value of buf_head at the time of acknowledgement.
- * @dccpav_ack_ackno - the Acknowledgement Number used for the packet
- *                    (HC-Sender seqno)
+ * @dccpav_records - list of dccp_ackvec_record
  * @dccpav_ack_nonce - the one-bit sum of the ECN Nonces for all State 0.
  *
- * @dccpav_buf_len     - circular buffer length
  * @dccpav_time                - the time in usecs
  * @dccpav_buf - circular buffer of acknowledgeable packets
  */
 struct dccp_ackvec {
        u64             dccpav_buf_ackno;
-       u64             dccpav_ack_seqno;
-       u64             dccpav_ack_ackno;
+       struct list_head dccpav_records;
        struct timeval  dccpav_time;
        u8              dccpav_buf_head;
        u8              dccpav_buf_tail;
        u8              dccpav_ack_ptr;
        u8              dccpav_sent_len;
        u8              dccpav_vec_len;
-       u8              dccpav_buf_len;
        u8              dccpav_buf_nonce;
        u8              dccpav_ack_nonce;
-       u8              dccpav_buf[0];
+       u8              dccpav_buf[DCCP_MAX_ACKVEC_LEN];
+};
+
+/** struct dccp_ackvec_record - ack vector record
+ *
+ * ACK vector record as defined in Appendix A of spec.
+ *
+ * The list is sorted by dccpavr_ack_seqno
+ *
+ * @dccpavr_node - node in dccpav_records
+ * @dccpavr_ack_seqno - sequence number of the packet this record was sent on
+ * @dccpavr_ack_ackno - sequence number being acknowledged
+ * @dccpavr_ack_ptr - pointer into dccpav_buf where this record starts
+ * @dccpavr_ack_nonce - dccpav_ack_nonce at the time this record was sent
+ * @dccpavr_sent_len - lenght of the record in dccpav_buf
+ */
+struct dccp_ackvec_record {
+       struct list_head dccpavr_node;
+       u64              dccpavr_ack_seqno;
+       u64              dccpavr_ack_ackno;
+       u8               dccpavr_ack_ptr;
+       u8               dccpavr_ack_nonce;
+       u8               dccpavr_sent_len;
 };
 
 struct sock;
 struct sk_buff;
 
 #ifdef CONFIG_IP_DCCP_ACKVEC
-extern struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len,
-                                         const gfp_t priority);
+extern int dccp_ackvec_init(void);
+extern void dccp_ackvec_exit(void);
+
+extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority);
 extern void dccp_ackvec_free(struct dccp_ackvec *av);
 
 extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
@@ -92,8 +111,16 @@ static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
        return av->dccpav_sent_len != av->dccpav_vec_len;
 }
 #else /* CONFIG_IP_DCCP_ACKVEC */
-static inline struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len,
-                                          const gfp_t priority)
+static inline int dccp_ackvec_init(void)
+{
+       return 0;
+}
+
+static inline void dccp_ackvec_exit(void)
+{
+}
+
+static inline struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
 {
        return NULL;
 }
index 9d8fc0e..ff05e59 100644 (file)
@@ -13,7 +13,7 @@
 
 #include "ccid.h"
 
-static struct ccid *ccids[CCID_MAX];
+static struct ccid_operations *ccids[CCID_MAX];
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 static atomic_t ccids_lockct = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(ccids_lock);
@@ -55,85 +55,202 @@ static inline void ccids_read_unlock(void)
 #define ccids_read_unlock() do { } while(0)
 #endif
 
-int ccid_register(struct ccid *ccid)
+static kmem_cache_t *ccid_kmem_cache_create(int obj_size, const char *fmt,...)
 {
-       int err;
+       kmem_cache_t *slab;
+       char slab_name_fmt[32], *slab_name;
+       va_list args;
 
-       if (ccid->ccid_init == NULL)
-               return -1;
+       va_start(args, fmt);
+       vsnprintf(slab_name_fmt, sizeof(slab_name_fmt), fmt, args);
+       va_end(args);
+
+       slab_name = kstrdup(slab_name_fmt, GFP_KERNEL);
+       if (slab_name == NULL)
+               return NULL;
+       slab = kmem_cache_create(slab_name, sizeof(struct ccid) + obj_size, 0,
+                                SLAB_HWCACHE_ALIGN, NULL, NULL);
+       if (slab == NULL)
+               kfree(slab_name);
+       return slab;
+}
+
+static void ccid_kmem_cache_destroy(kmem_cache_t *slab)
+{
+       if (slab != NULL) {
+               const char *name = kmem_cache_name(slab);
+
+               kmem_cache_destroy(slab);
+               kfree(name);
+       }
+}
+
+int ccid_register(struct ccid_operations *ccid_ops)
+{
+       int err = -ENOBUFS;
+
+       ccid_ops->ccid_hc_rx_slab =
+                       ccid_kmem_cache_create(ccid_ops->ccid_hc_rx_obj_size,
+                                              "%s_hc_rx_sock",
+                                              ccid_ops->ccid_name);
+       if (ccid_ops->ccid_hc_rx_slab == NULL)
+               goto out;
+
+       ccid_ops->ccid_hc_tx_slab =
+                       ccid_kmem_cache_create(ccid_ops->ccid_hc_tx_obj_size,
+                                              "%s_hc_tx_sock",
+                                              ccid_ops->ccid_name);
+       if (ccid_ops->ccid_hc_tx_slab == NULL)
+               goto out_free_rx_slab;
 
        ccids_write_lock();
        err = -EEXIST;
-       if (ccids[ccid->ccid_id] == NULL) {
-               ccids[ccid->ccid_id] = ccid;
+       if (ccids[ccid_ops->ccid_id] == NULL) {
+               ccids[ccid_ops->ccid_id] = ccid_ops;
                err = 0;
        }
        ccids_write_unlock();
-       if (err == 0)
-               pr_info("CCID: Registered CCID %d (%s)\n",
-                       ccid->ccid_id, ccid->ccid_name);
+       if (err != 0)
+               goto out_free_tx_slab;
+
+       pr_info("CCID: Registered CCID %d (%s)\n",
+               ccid_ops->ccid_id, ccid_ops->ccid_name);
+out:
        return err;
+out_free_tx_slab:
+       ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
+       ccid_ops->ccid_hc_tx_slab = NULL;
+       goto out;
+out_free_rx_slab:
+       ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
+       ccid_ops->ccid_hc_rx_slab = NULL;
+       goto out;
 }
 
 EXPORT_SYMBOL_GPL(ccid_register);
 
-int ccid_unregister(struct ccid *ccid)
+int ccid_unregister(struct ccid_operations *ccid_ops)
 {
        ccids_write_lock();
-       ccids[ccid->ccid_id] = NULL;
+       ccids[ccid_ops->ccid_id] = NULL;
        ccids_write_unlock();
+
+       ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab);
+       ccid_ops->ccid_hc_tx_slab = NULL;
+       ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab);
+       ccid_ops->ccid_hc_rx_slab = NULL;
+
        pr_info("CCID: Unregistered CCID %d (%s)\n",
-               ccid->ccid_id, ccid->ccid_name);
+               ccid_ops->ccid_id, ccid_ops->ccid_name);
        return 0;
 }
 
 EXPORT_SYMBOL_GPL(ccid_unregister);
 
-struct ccid *ccid_init(unsigned char id, struct sock *sk)
+struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
 {
-       struct ccid *ccid;
+       struct ccid_operations *ccid_ops;
+       struct ccid *ccid = NULL;
 
+       ccids_read_lock();
 #ifdef CONFIG_KMOD
-       if (ccids[id] == NULL)
+       if (ccids[id] == NULL) {
+               /* We only try to load if in process context */
+               ccids_read_unlock();
+               if (gfp & GFP_ATOMIC)
+                       goto out;
                request_module("net-dccp-ccid-%d", id);
+               ccids_read_lock();
+       }
 #endif
-       ccids_read_lock();
+       ccid_ops = ccids[id];
+       if (ccid_ops == NULL)
+               goto out_unlock;
 
-       ccid = ccids[id];
-       if (ccid == NULL)
-               goto out;
+       if (!try_module_get(ccid_ops->ccid_owner))
+               goto out_unlock;
 
-       if (!try_module_get(ccid->ccid_owner))
-               goto out_err;
+       ccids_read_unlock();
 
-       if (ccid->ccid_init(sk) != 0)
+       ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab :
+                                    ccid_ops->ccid_hc_tx_slab, gfp);
+       if (ccid == NULL)
                goto out_module_put;
+       ccid->ccid_ops = ccid_ops;
+       if (rx) {
+               memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size);
+               if (ccid->ccid_ops->ccid_hc_rx_init != NULL &&
+                   ccid->ccid_ops->ccid_hc_rx_init(ccid, sk) != 0)
+                       goto out_free_ccid;
+       } else {
+               memset(ccid + 1, 0, ccid_ops->ccid_hc_tx_obj_size);
+               if (ccid->ccid_ops->ccid_hc_tx_init != NULL &&
+                   ccid->ccid_ops->ccid_hc_tx_init(ccid, sk) != 0)
+                       goto out_free_ccid;
+       }
 out:
-       ccids_read_unlock();
        return ccid;
-out_module_put:
-       module_put(ccid->ccid_owner);
-out_err:
+out_unlock:
+       ccids_read_unlock();
+       goto out;
+out_free_ccid:
+       kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab :
+                       ccid_ops->ccid_hc_tx_slab, ccid);
        ccid = NULL;
+out_module_put:
+       module_put(ccid_ops->ccid_owner);
        goto out;
 }
 
-EXPORT_SYMBOL_GPL(ccid_init);
+EXPORT_SYMBOL_GPL(ccid_new);
+
+struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp)
+{
+       return ccid_new(id, sk, 1, gfp);
+}
+
+EXPORT_SYMBOL_GPL(ccid_hc_rx_new);
+
+struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk,  gfp_t gfp)
+{
+       return ccid_new(id, sk, 0, gfp);
+}
+
+EXPORT_SYMBOL_GPL(ccid_hc_tx_new);
 
-void ccid_exit(struct ccid *ccid, struct sock *sk)
+static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
 {
+       struct ccid_operations *ccid_ops;
+
        if (ccid == NULL)
                return;
 
+       ccid_ops = ccid->ccid_ops;
+       if (rx) {
+               if (ccid_ops->ccid_hc_rx_exit != NULL)
+                       ccid_ops->ccid_hc_rx_exit(sk);
+               kmem_cache_free(ccid_ops->ccid_hc_rx_slab,  ccid);
+       } else {
+               if (ccid_ops->ccid_hc_tx_exit != NULL)
+                       ccid_ops->ccid_hc_tx_exit(sk);
+               kmem_cache_free(ccid_ops->ccid_hc_tx_slab,  ccid);
+       }
        ccids_read_lock();
+       if (ccids[ccid_ops->ccid_id] != NULL)
+               module_put(ccid_ops->ccid_owner);
+       ccids_read_unlock();
+}
 
-       if (ccids[ccid->ccid_id] != NULL) {
-               if (ccid->ccid_exit != NULL)
-                       ccid->ccid_exit(sk);
-               module_put(ccid->ccid_owner);
-       }
+void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk)
+{
+       ccid_delete(ccid, sk, 1);
+}
 
-       ccids_read_unlock();
+EXPORT_SYMBOL_GPL(ccid_hc_rx_delete);
+
+void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk)
+{
+       ccid_delete(ccid, sk, 0);
 }
 
-EXPORT_SYMBOL_GPL(ccid_exit);
+EXPORT_SYMBOL_GPL(ccid_hc_tx_delete);
index de681c6..f7eb6c6 100644 (file)
 
 struct tcp_info;
 
-struct ccid {
+struct ccid_operations {
        unsigned char   ccid_id;
        const char      *ccid_name;
        struct module   *ccid_owner;
-       int             (*ccid_init)(struct sock *sk);
-       void            (*ccid_exit)(struct sock *sk);
-       int             (*ccid_hc_rx_init)(struct sock *sk);
-       int             (*ccid_hc_tx_init)(struct sock *sk);
+       kmem_cache_t    *ccid_hc_rx_slab;
+       __u32           ccid_hc_rx_obj_size;
+       kmem_cache_t    *ccid_hc_tx_slab;
+       __u32           ccid_hc_tx_obj_size;
+       int             (*ccid_hc_rx_init)(struct ccid *ccid, struct sock *sk);
+       int             (*ccid_hc_tx_init)(struct ccid *ccid, struct sock *sk);
        void            (*ccid_hc_rx_exit)(struct sock *sk);
        void            (*ccid_hc_tx_exit)(struct sock *sk);
        void            (*ccid_hc_rx_packet_recv)(struct sock *sk,
@@ -39,9 +41,9 @@ struct ccid {
                                                    unsigned char option,
                                                    unsigned char len, u16 idx,
                                                    unsigned char* value);
-       void            (*ccid_hc_rx_insert_options)(struct sock *sk,
+       int             (*ccid_hc_rx_insert_options)(struct sock *sk,
                                                     struct sk_buff *skb);
-       void            (*ccid_hc_tx_insert_options)(struct sock *sk,
+       int             (*ccid_hc_tx_insert_options)(struct sock *sk,
                                                     struct sk_buff *skb);
        void            (*ccid_hc_tx_packet_recv)(struct sock *sk,
                                                  struct sk_buff *skb);
@@ -67,75 +69,58 @@ struct ccid {
                                                 int __user *optlen);
 };
 
-extern int        ccid_register(struct ccid *ccid);
-extern int        ccid_unregister(struct ccid *ccid);
+extern int ccid_register(struct ccid_operations *ccid_ops);
+extern int ccid_unregister(struct ccid_operations *ccid_ops);
 
-extern struct ccid *ccid_init(unsigned char id, struct sock *sk);
-extern void       ccid_exit(struct ccid *ccid, struct sock *sk);
+struct ccid {
+       struct ccid_operations *ccid_ops;
+       char                   ccid_priv[0];
+};
 
-static inline void __ccid_get(struct ccid *ccid)
+static inline void *ccid_priv(const struct ccid *ccid)
 {
-       __module_get(ccid->ccid_owner);
+       return (void *)ccid->ccid_priv;
 }
 
+extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
+                            gfp_t gfp);
+
+extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
+                                  gfp_t gfp);
+extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
+                                  gfp_t gfp);
+
+extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
+extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
+
 static inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk,
                                         struct sk_buff *skb, int len)
 {
        int rc = 0;
-       if (ccid->ccid_hc_tx_send_packet != NULL)
-               rc = ccid->ccid_hc_tx_send_packet(sk, skb, len);
+       if (ccid->ccid_ops->ccid_hc_tx_send_packet != NULL)
+               rc = ccid->ccid_ops->ccid_hc_tx_send_packet(sk, skb, len);
        return rc;
 }
 
 static inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk,
                                          int more, int len)
 {
-       if (ccid->ccid_hc_tx_packet_sent != NULL)
-               ccid->ccid_hc_tx_packet_sent(sk, more, len);
-}
-
-static inline int ccid_hc_rx_init(struct ccid *ccid, struct sock *sk)
-{
-       int rc = 0;
-       if (ccid->ccid_hc_rx_init != NULL)
-               rc = ccid->ccid_hc_rx_init(sk);
-       return rc;
-}
-
-static inline int ccid_hc_tx_init(struct ccid *ccid, struct sock *sk)
-{
-       int rc = 0;
-       if (ccid->ccid_hc_tx_init != NULL)
-               rc = ccid->ccid_hc_tx_init(sk);
-       return rc;
-}
-
-static inline void ccid_hc_rx_exit(struct ccid *ccid, struct sock *sk)
-{
-       if (ccid != NULL && ccid->ccid_hc_rx_exit != NULL &&
-           dccp_sk(sk)->dccps_hc_rx_ccid_private != NULL)
-               ccid->ccid_hc_rx_exit(sk);
-}
-
-static inline void ccid_hc_tx_exit(struct ccid *ccid, struct sock *sk)
-{
-       if (ccid != NULL && ccid->ccid_hc_tx_exit != NULL &&
-           dccp_sk(sk)->dccps_hc_tx_ccid_private != NULL)
-               ccid->ccid_hc_tx_exit(sk);
+       if (ccid->ccid_ops->ccid_hc_tx_packet_sent != NULL)
+               ccid->ccid_ops->ccid_hc_tx_packet_sent(sk, more, len);
 }
 
 static inline void ccid_hc_rx_packet_recv(struct ccid *ccid, struct sock *sk,
                                          struct sk_buff *skb)
 {
-       if (ccid->ccid_hc_rx_packet_recv != NULL)
-               ccid->ccid_hc_rx_packet_recv(sk, skb);
+       if (ccid->ccid_ops->ccid_hc_rx_packet_recv != NULL)
+               ccid->ccid_ops->ccid_hc_rx_packet_recv(sk, skb);
 }
 
 static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk,
                                          struct sk_buff *skb)
 {
-       if (ccid->ccid_hc_tx_packet_recv != NULL)
-               ccid->ccid_hc_tx_packet_recv(sk, skb);
+       if (ccid->ccid_ops->ccid_hc_tx_packet_recv != NULL)
+               ccid->ccid_ops->ccid_hc_tx_packet_recv(sk, skb);
 }
 
 static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
@@ -144,8 +129,8 @@ static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
                                           unsigned char* value)
 {
        int rc = 0;
-       if (ccid->ccid_hc_tx_parse_options != NULL)
-               rc = ccid->ccid_hc_tx_parse_options(sk, option, len, idx,
+       if (ccid->ccid_ops->ccid_hc_tx_parse_options != NULL)
+               rc = ccid->ccid_ops->ccid_hc_tx_parse_options(sk, option, len, idx,
                                                    value);
        return rc;
 }
@@ -156,37 +141,39 @@ static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
                                           unsigned char* value)
 {
        int rc = 0;
-       if (ccid->ccid_hc_rx_parse_options != NULL)
-               rc = ccid->ccid_hc_rx_parse_options(sk, option, len, idx, value);
+       if (ccid->ccid_ops->ccid_hc_rx_parse_options != NULL)
+               rc = ccid->ccid_ops->ccid_hc_rx_parse_options(sk, option, len, idx, value);
        return rc;
 }
 
-static inline void ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk,
-                                            struct sk_buff *skb)
+static inline int ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk,
+                                           struct sk_buff *skb)
 {
-       if (ccid->ccid_hc_tx_insert_options != NULL)
-               ccid->ccid_hc_tx_insert_options(sk, skb);
+       if (ccid->ccid_ops->ccid_hc_tx_insert_options != NULL)
+               return ccid->ccid_ops->ccid_hc_tx_insert_options(sk, skb);
+       return 0;
 }
 
-static inline void ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
-                                            struct sk_buff *skb)
+static inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
+                                           struct sk_buff *skb)
 {
-       if (ccid->ccid_hc_rx_insert_options != NULL)
-               ccid->ccid_hc_rx_insert_options(sk, skb);
+       if (ccid->ccid_ops->ccid_hc_rx_insert_options != NULL)
+               return ccid->ccid_ops->ccid_hc_rx_insert_options(sk, skb);
+       return 0;
 }
 
 static inline void ccid_hc_rx_get_info(struct ccid *ccid, struct sock *sk,
                                       struct tcp_info *info)
 {
-       if (ccid->ccid_hc_rx_get_info != NULL)
-               ccid->ccid_hc_rx_get_info(sk, info);
+       if (ccid->ccid_ops->ccid_hc_rx_get_info != NULL)
+               ccid->ccid_ops->ccid_hc_rx_get_info(sk, info);
 }
 
 static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk,
                                       struct tcp_info *info)
 {
-       if (ccid->ccid_hc_tx_get_info != NULL)
-               ccid->ccid_hc_tx_get_info(sk, info);
+       if (ccid->ccid_ops->ccid_hc_tx_get_info != NULL)
+               ccid->ccid_ops->ccid_hc_tx_get_info(sk, info);
 }
 
 static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk,
@@ -194,8 +181,8 @@ static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk,
                                        u32 __user *optval, int __user *optlen)
 {
        int rc = -ENOPROTOOPT;
-       if (ccid->ccid_hc_rx_getsockopt != NULL)
-               rc = ccid->ccid_hc_rx_getsockopt(sk, optname, len,
+       if (ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL)
+               rc = ccid->ccid_ops->ccid_hc_rx_getsockopt(sk, optname, len,
                                                 optval, optlen);
        return rc;
 }
@@ -205,8 +192,8 @@ static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk,
                                        u32 __user *optval, int __user *optlen)
 {
        int rc = -ENOPROTOOPT;
-       if (ccid->ccid_hc_tx_getsockopt != NULL)
-               rc = ccid->ccid_hc_tx_getsockopt(sk, optname, len,
+       if (ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL)
+               rc = ccid->ccid_ops->ccid_hc_tx_getsockopt(sk, optname, len,
                                                 optval, optlen);
        return rc;
 }
index 7684d83..ca00191 100644 (file)
@@ -1,9 +1,39 @@
 menu "DCCP CCIDs Configuration (EXPERIMENTAL)"
        depends on IP_DCCP && EXPERIMENTAL
 
+config IP_DCCP_CCID2
+       tristate "CCID2 (TCP-Like) (EXPERIMENTAL)"
+       depends on IP_DCCP
+       def_tristate IP_DCCP
+       select IP_DCCP_ACKVEC
+       ---help---
+         CCID 2, TCP-like Congestion Control, denotes Additive Increase,
+         Multiplicative Decrease (AIMD) congestion control with behavior
+         modelled directly on TCP, including congestion window, slow start,
+         timeouts, and so forth [RFC 2581].  CCID 2 achieves maximum
+         bandwidth over the long term, consistent with the use of end-to-end
+         congestion control, but halves its congestion window in response to
+         each congestion event.  This leads to the abrupt rate changes
+         typical of TCP.  Applications should use CCID 2 if they prefer
+         maximum bandwidth utilization to steadiness of rate.  This is often
+         the case for applications that are not playing their data directly
+         to the user.  For example, a hypothetical application that
+         transferred files over DCCP, using application-level retransmissions
+         for lost packets, would prefer CCID 2 to CCID 3.  On-line games may
+         also prefer CCID 2.
+
+         CCID 2 is further described in:
+         http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid2-10.txt
+
+         This text was extracted from:
+         http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
+
+         If in doubt, say M.
+
 config IP_DCCP_CCID3
-       tristate "CCID3 (TFRC) (EXPERIMENTAL)"
+       tristate "CCID3 (TCP-Friendly) (EXPERIMENTAL)"
        depends on IP_DCCP
+       def_tristate IP_DCCP
        ---help---
          CCID 3 denotes TCP-Friendly Rate Control (TFRC), an equation-based
          rate-controlled congestion control mechanism.  TFRC is designed to
@@ -15,10 +45,15 @@ config IP_DCCP_CCID3
          suitable than CCID 2 for applications such streaming media where a
          relatively smooth sending rate is of importance.
 
-         CCID 3 is further described in [CCID 3 PROFILE]. The TFRC
-         congestion control algorithms were initially described in RFC 3448.
+         CCID 3 is further described in:
+
+         http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid3-11.txt.
+
+         The TFRC congestion control algorithms were initially described in
+         RFC 3448.
 
-         This text was extracted from draft-ietf-dccp-spec-11.txt.
+         This text was extracted from:
+         http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
          
          If in doubt, say M.
 
index 956f79f..438f20b 100644 (file)
@@ -2,4 +2,8 @@ obj-$(CONFIG_IP_DCCP_CCID3) += dccp_ccid3.o
 
 dccp_ccid3-y := ccid3.o
 
+obj-$(CONFIG_IP_DCCP_CCID2) += dccp_ccid2.o
+
+dccp_ccid2-y := ccid2.o
+
 obj-y += lib/
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
new file mode 100644 (file)
index 0000000..d4f9e2d
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ *  net/dccp/ccids/ccid2.c
+ *
+ *  Copyright (c) 2005, 2006 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *  Changes to meet Linux coding standards, and DCCP infrastructure fixes.
+ *
+ *  Copyright (c) 2006 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This implementation should follow: draft-ietf-dccp-ccid2-10.txt
+ *
+ * BUGS:
+ * - sequence number wrapping
+ * - jiffies wrapping
+ */
+
+#include <linux/config.h>
+#include "../ccid.h"
+#include "../dccp.h"
+#include "ccid2.h"
+
+static int ccid2_debug;
+
+#undef CCID2_DEBUG
+#ifdef CCID2_DEBUG
+#define ccid2_pr_debug(format, a...) \
+        do { if (ccid2_debug) \
+                printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \
+        } while (0)
+#else
+#define ccid2_pr_debug(format, a...)
+#endif
+
+static const int ccid2_seq_len = 128;
+
+#ifdef CCID2_DEBUG
+static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
+{
+       int len = 0;
+       int pipe = 0;
+       struct ccid2_seq *seqp = hctx->ccid2hctx_seqh;
+
+       /* there is data in the chain */
+       if (seqp != hctx->ccid2hctx_seqt) {
+               seqp = seqp->ccid2s_prev;
+               len++;
+               if (!seqp->ccid2s_acked)
+                       pipe++;
+
+               while (seqp != hctx->ccid2hctx_seqt) {
+                       struct ccid2_seq *prev = seqp->ccid2s_prev;
+
+                       len++;
+                       if (!prev->ccid2s_acked)
+                               pipe++;
+
+                       /* packets are sent sequentially */
+                       BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq);
+                       BUG_ON(seqp->ccid2s_sent < prev->ccid2s_sent);
+                       BUG_ON(len > ccid2_seq_len);
+
+                       seqp = prev;
+               }
+       }
+
+       BUG_ON(pipe != hctx->ccid2hctx_pipe);
+       ccid2_pr_debug("len of chain=%d\n", len);
+
+       do {
+               seqp = seqp->ccid2s_prev;
+               len++;
+               BUG_ON(len > ccid2_seq_len);
+       } while (seqp != hctx->ccid2hctx_seqh);
+
+       BUG_ON(len != ccid2_seq_len);
+       ccid2_pr_debug("total len=%d\n", len);
+}
+#else
+#define ccid2_hc_tx_check_sanity(hctx) do {} while (0)
+#endif
+
+static int ccid2_hc_tx_send_packet(struct sock *sk,
+                                  struct sk_buff *skb, int len)
+{
+       struct ccid2_hc_tx_sock *hctx;
+
+       switch (DCCP_SKB_CB(skb)->dccpd_type) {
+       case 0: /* XXX data packets from userland come through like this */
+       case DCCP_PKT_DATA:
+       case DCCP_PKT_DATAACK:
+               break;
+       /* No congestion control on other packets */
+       default:
+               return 0;
+       }
+
+        hctx = ccid2_hc_tx_sk(sk);
+
+       ccid2_pr_debug("pipe=%d cwnd=%d\n", hctx->ccid2hctx_pipe,
+                      hctx->ccid2hctx_cwnd);
+
+       if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd) {
+               /* OK we can send... make sure previous packet was sent off */
+               if (!hctx->ccid2hctx_sendwait) {
+                       hctx->ccid2hctx_sendwait = 1;
+                       return 0;
+               }
+       }
+
+       return 100; /* XXX */
+}
+
+static void ccid2_change_l_ack_ratio(struct sock *sk, int val)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       /*
+        * XXX I don't really agree with val != 2.  If cwnd is 1, ack ratio
+        * should be 1... it shouldn't be allowed to become 2.
+        * -sorbo.
+        */
+       if (val != 2) {
+               const struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+               int max = hctx->ccid2hctx_cwnd / 2;
+
+               /* round up */
+               if (hctx->ccid2hctx_cwnd & 1)
+                       max++;
+
+               if (val > max)
+                       val = max;
+       }
+
+       ccid2_pr_debug("changing local ack ratio to %d\n", val);
+       WARN_ON(val <= 0);
+       dp->dccps_l_ack_ratio = val;
+}
+
+static void ccid2_change_cwnd(struct sock *sk, int val)
+{
+       struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+       if (val == 0)
+               val = 1;
+
+       /* XXX do we need to change ack ratio? */
+       ccid2_pr_debug("change cwnd to %d\n", val);
+
+       BUG_ON(val < 1);
+       hctx->ccid2hctx_cwnd = val;
+}
+
+static void ccid2_start_rto_timer(struct sock *sk);
+
+static void ccid2_hc_tx_rto_expire(unsigned long data)
+{
+       struct sock *sk = (struct sock *)data;
+       struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+       long s;
+
+       bh_lock_sock(sk);
+       if (sock_owned_by_user(sk)) {
+               sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
+                              jiffies + HZ / 5);
+               goto out;
+       }
+
+       ccid2_pr_debug("RTO_EXPIRE\n");
+
+       ccid2_hc_tx_check_sanity(hctx);
+
+       /* back-off timer */
+       hctx->ccid2hctx_rto <<= 1;
+
+       s = hctx->ccid2hctx_rto / HZ;
+       if (s > 60)
+               hctx->ccid2hctx_rto = 60 * HZ;
+
+       ccid2_start_rto_timer(sk);
+
+       /* adjust pipe, cwnd etc */
+       hctx->ccid2hctx_pipe = 0;
+       hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1;
+       if (hctx->ccid2hctx_ssthresh < 2)
+               hctx->ccid2hctx_ssthresh = 2;
+       ccid2_change_cwnd(sk, 1);
+
+       /* clear state about stuff we sent */
+       hctx->ccid2hctx_seqt    = hctx->ccid2hctx_seqh;
+       hctx->ccid2hctx_ssacks  = 0;
+       hctx->ccid2hctx_acks    = 0;
+       hctx->ccid2hctx_sent    = 0;
+
+       /* clear ack ratio state. */
+       hctx->ccid2hctx_arsent   = 0;
+       hctx->ccid2hctx_ackloss  = 0;
+       hctx->ccid2hctx_rpseq    = 0;
+       hctx->ccid2hctx_rpdupack = -1;
+       ccid2_change_l_ack_ratio(sk, 1);
+       ccid2_hc_tx_check_sanity(hctx);
+out:
+       bh_unlock_sock(sk);
+       sock_put(sk);
+}
+
+static void ccid2_start_rto_timer(struct sock *sk)
+{
+       struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+       ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->ccid2hctx_rto);
+
+       BUG_ON(timer_pending(&hctx->ccid2hctx_rtotimer));
+       sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
+                      jiffies + hctx->ccid2hctx_rto);
+}
+
+static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+       u64 seq;
+
+       ccid2_hc_tx_check_sanity(hctx);
+
+       BUG_ON(!hctx->ccid2hctx_sendwait);
+       hctx->ccid2hctx_sendwait = 0;
+       hctx->ccid2hctx_pipe++;
+       BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+       /* There is an issue.  What if another packet is sent between
+        * packet_send() and packet_sent().  Then the sequence number would be
+        * wrong.
+        * -sorbo.
+        */
+       seq = dp->dccps_gss;
+
+       hctx->ccid2hctx_seqh->ccid2s_seq   = seq;
+       hctx->ccid2hctx_seqh->ccid2s_acked = 0;
+       hctx->ccid2hctx_seqh->ccid2s_sent  = jiffies;
+       hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqh->ccid2s_next;
+
+       ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd,
+                      hctx->ccid2hctx_pipe);
+
+       if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) {
+               /* XXX allocate more space */
+               WARN_ON(1);
+       }
+
+       hctx->ccid2hctx_sent++;
+
+       /* Ack Ratio.  Need to maintain a concept of how many windows we sent */
+       hctx->ccid2hctx_arsent++;
+       /* We had an ack loss in this window... */
+       if (hctx->ccid2hctx_ackloss) {
+               if (hctx->ccid2hctx_arsent >= hctx->ccid2hctx_cwnd) {
+                       hctx->ccid2hctx_arsent  = 0;
+                       hctx->ccid2hctx_ackloss = 0;
+               }
+       } else {
+               /* No acks lost up to now... */
+               /* decrease ack ratio if enough packets were sent */
+               if (dp->dccps_l_ack_ratio > 1) {
+                       /* XXX don't calculate denominator each time */
+                       int denom = dp->dccps_l_ack_ratio * dp->dccps_l_ack_ratio -
+                                   dp->dccps_l_ack_ratio;
+
+                       denom = hctx->ccid2hctx_cwnd * hctx->ccid2hctx_cwnd / denom;
+
+                       if (hctx->ccid2hctx_arsent >= denom) {
+                               ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1);
+                               hctx->ccid2hctx_arsent = 0;
+                       }
+               } else {
+                       /* we can't increase ack ratio further [1] */
+                       hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/
+               }
+       }
+
+       /* setup RTO timer */
+       if (!timer_pending(&hctx->ccid2hctx_rtotimer))
+               ccid2_start_rto_timer(sk);
+
+#ifdef CCID2_DEBUG
+       ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe);
+       ccid2_pr_debug("Sent: seq=%llu\n", seq);
+       do {
+               struct ccid2_seq *seqp = hctx->ccid2hctx_seqt;
+
+               while (seqp != hctx->ccid2hctx_seqh) {
+                       ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
+                                      seqp->ccid2s_seq, seqp->ccid2s_acked,
+                                      seqp->ccid2s_sent);
+                       seqp = seqp->ccid2s_next;
+               }
+       } while (0);
+       ccid2_pr_debug("=========\n");
+       ccid2_hc_tx_check_sanity(hctx);
+#endif
+}
+
+/* XXX Lame code duplication!
+ * returns -1 if none was found.
+ * else returns the next offset to use in the function call.
+ */
+static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset,
+                          unsigned char **vec, unsigned char *veclen)
+{
+        const struct dccp_hdr *dh = dccp_hdr(skb);
+        unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
+        unsigned char *opt_ptr;
+        const unsigned char *opt_end = (unsigned char *)dh +
+                                        (dh->dccph_doff * 4);
+        unsigned char opt, len;
+        unsigned char *value;
+
+       BUG_ON(offset < 0);
+       options += offset;
+       opt_ptr = options;
+       if (opt_ptr >= opt_end)
+               return -1;
+
+       while (opt_ptr != opt_end) {
+                opt   = *opt_ptr++;
+                len   = 0;
+                value = NULL;
+
+                /* Check if this isn't a single byte option */
+                if (opt > DCCPO_MAX_RESERVED) {
+                        if (opt_ptr == opt_end)
+                                goto out_invalid_option;
+
+                        len = *opt_ptr++;
+                        if (len < 3)
+                                goto out_invalid_option;
+                        /*
+                         * Remove the type and len fields, leaving
+                         * just the value size
+                         */
+                        len     -= 2;
+                        value   = opt_ptr;
+                        opt_ptr += len;
+
+                        if (opt_ptr > opt_end)
+                                goto out_invalid_option;
+                }
+
+               switch (opt) {
+               case DCCPO_ACK_VECTOR_0:
+               case DCCPO_ACK_VECTOR_1:
+                       *vec    = value;
+                       *veclen = len;
+                       return offset + (opt_ptr - options);
+               }
+       }
+
+       return -1;
+
+out_invalid_option:
+       BUG_ON(1); /* should never happen... options were previously parsed ! */
+       return -1;
+}
+
+static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
+{
+       struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+       sk_stop_timer(sk, &hctx->ccid2hctx_rtotimer);
+       ccid2_pr_debug("deleted RTO timer\n");
+}
+
+static inline void ccid2_new_ack(struct sock *sk,
+                                struct ccid2_seq *seqp,
+                                unsigned int *maxincr)
+{
+       struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+       /* slow start */
+       if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh) {
+               hctx->ccid2hctx_acks = 0;
+
+               /* We can increase cwnd at most maxincr [ack_ratio/2] */
+               if (*maxincr) {
+                       /* increase every 2 acks */
+                       hctx->ccid2hctx_ssacks++;
+                       if (hctx->ccid2hctx_ssacks == 2) {
+                               ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+                               hctx->ccid2hctx_ssacks = 0;
+                               *maxincr = *maxincr - 1;
+                       }
+               } else {
+                       /* increased cwnd enough for this single ack */
+                       hctx->ccid2hctx_ssacks = 0;
+               }
+       } else {
+               hctx->ccid2hctx_ssacks = 0;
+               hctx->ccid2hctx_acks++;
+
+               if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) {
+                       ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+                       hctx->ccid2hctx_acks = 0;
+               }
+       }
+
+       /* update RTO */
+       if (hctx->ccid2hctx_srtt == -1 ||
+           (jiffies - hctx->ccid2hctx_lastrtt) >= hctx->ccid2hctx_srtt) {
+               unsigned long r = jiffies - seqp->ccid2s_sent;
+               int s;
+
+               /* first measurement */
+               if (hctx->ccid2hctx_srtt == -1) {
+                       ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
+                                      r, jiffies, seqp->ccid2s_seq);
+                       hctx->ccid2hctx_srtt = r;
+                       hctx->ccid2hctx_rttvar = r >> 1;
+               } else {
+                       /* RTTVAR */
+                       long tmp = hctx->ccid2hctx_srtt - r;
+                       if (tmp < 0)
+                               tmp *= -1;
+
+                       tmp >>= 2;
+                       hctx->ccid2hctx_rttvar *= 3;
+                       hctx->ccid2hctx_rttvar >>= 2;
+                       hctx->ccid2hctx_rttvar += tmp;
+
+                       /* SRTT */
+                       hctx->ccid2hctx_srtt *= 7;
+                       hctx->ccid2hctx_srtt >>= 3;
+                       tmp = r >> 3;
+                       hctx->ccid2hctx_srtt += tmp;
+               }
+               s = hctx->ccid2hctx_rttvar << 2;
+               /* clock granularity is 1 when based on jiffies */
+               if (!s)
+                       s = 1;
+               hctx->ccid2hctx_rto = hctx->ccid2hctx_srtt + s;
+
+               /* must be at least a second */
+               s = hctx->ccid2hctx_rto / HZ;
+               /* DCCP doesn't require this [but I like it cuz my code sux] */
+#if 1
+               if (s < 1)
+                       hctx->ccid2hctx_rto = HZ;
+#endif
+               /* max 60 seconds */
+               if (s > 60)
+                       hctx->ccid2hctx_rto = HZ * 60;
+
+               hctx->ccid2hctx_lastrtt = jiffies;
+
+               ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
+                              hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
+                              hctx->ccid2hctx_rto, HZ, r);
+               hctx->ccid2hctx_sent = 0;
+       }
+
+       /* we got a new ack, so re-start RTO timer */
+       ccid2_hc_tx_kill_rto_timer(sk);
+       ccid2_start_rto_timer(sk);
+}
+
+static void ccid2_hc_tx_dec_pipe(struct sock *sk)
+{
+       struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+       hctx->ccid2hctx_pipe--;
+       BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+       if (hctx->ccid2hctx_pipe == 0)
+               ccid2_hc_tx_kill_rto_timer(sk);
+}
+
+static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+       u64 ackno, seqno;
+       struct ccid2_seq *seqp;
+       unsigned char *vector;
+       unsigned char veclen;
+       int offset = 0;
+       int done = 0;
+       int loss = 0;
+       unsigned int maxincr = 0;
+
+       ccid2_hc_tx_check_sanity(hctx);
+       /* check reverse path congestion */
+       seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+
+       /* XXX this whole "algorithm" is broken.  Need to fix it to keep track
+        * of the seqnos of the dupacks so that rpseq and rpdupack are correct
+        * -sorbo.
+        */
+       /* need to bootstrap */
+       if (hctx->ccid2hctx_rpdupack == -1) {
+               hctx->ccid2hctx_rpdupack = 0;
+               hctx->ccid2hctx_rpseq = seqno;
+       } else {
+               /* check if packet is consecutive */
+               if ((hctx->ccid2hctx_rpseq + 1) == seqno)
+                       hctx->ccid2hctx_rpseq++;
+               /* it's a later packet */
+               else if (after48(seqno, hctx->ccid2hctx_rpseq)) {
+                       hctx->ccid2hctx_rpdupack++;
+
+                       /* check if we got enough dupacks */
+                       if (hctx->ccid2hctx_rpdupack >=
+                           hctx->ccid2hctx_numdupack) {
+                               hctx->ccid2hctx_rpdupack = -1; /* XXX lame */
+                               hctx->ccid2hctx_rpseq = 0;
+
+                               ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio << 1);
+                       }
+               }
+       }
+
+       /* check forward path congestion */
+       /* still didn't send out new data packets */
+       if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt)
+               return;
+
+       switch (DCCP_SKB_CB(skb)->dccpd_type) {
+       case DCCP_PKT_ACK:
+       case DCCP_PKT_DATAACK:
+               break;
+       default:
+               return;
+       }
+
+       ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
+       seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+
+       /* If in slow-start, cwnd can increase at most Ack Ratio / 2 packets for
+        * this single ack.  I round up.
+        * -sorbo.
+        */
+       maxincr = dp->dccps_l_ack_ratio >> 1;
+       maxincr++;
+
+       /* go through all ack vectors */
+       while ((offset = ccid2_ackvector(sk, skb, offset,
+                                        &vector, &veclen)) != -1) {
+               /* go through this ack vector */
+               while (veclen--) {
+                       const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
+                       u64 ackno_end_rl;
+
+                       dccp_set_seqno(&ackno_end_rl, ackno - rl);
+                       ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno,
+                                      ackno_end_rl);
+                       /* if the seqno we are analyzing is larger than the
+                        * current ackno, then move towards the tail of our
+                        * seqnos.
+                        */
+                       while (after48(seqp->ccid2s_seq, ackno)) {
+                               if (seqp == hctx->ccid2hctx_seqt) {
+                                       done = 1;
+                                       break;
+                               }
+                               seqp = seqp->ccid2s_prev;
+                       }
+                       if (done)
+                               break;
+
+                       /* check all seqnos in the range of the vector
+                        * run length
+                        */
+                       while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
+                               const u8 state = (*vector &
+                                                 DCCP_ACKVEC_STATE_MASK) >> 6;
+
+                               /* new packet received or marked */
+                               if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
+                                   !seqp->ccid2s_acked) {
+                                       if (state ==
+                                           DCCP_ACKVEC_STATE_ECN_MARKED) {
+                                               loss = 1;
+                                       } else
+                                               ccid2_new_ack(sk, seqp,
+                                                             &maxincr);
+
+                                       seqp->ccid2s_acked = 1;
+                                       ccid2_pr_debug("Got ack for %llu\n",
+                                                      seqp->ccid2s_seq);
+                                       ccid2_hc_tx_dec_pipe(sk);
+                               }
+                               if (seqp == hctx->ccid2hctx_seqt) {
+                                       done = 1;
+                                       break;
+                               }
+                               seqp = seqp->ccid2s_next;
+                       }
+                       if (done)
+                               break;
+
+
+                       dccp_set_seqno(&ackno, ackno_end_rl - 1);
+                       vector++;
+               }
+               if (done)
+                       break;
+       }
+
+       /* The state about what is acked should be correct now
+        * Check for NUMDUPACK
+        */
+       seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+       done = 0;
+       while (1) {
+               if (seqp->ccid2s_acked) {
+                       done++;
+                       if (done == hctx->ccid2hctx_numdupack)
+                               break;
+               }
+               if (seqp == hctx->ccid2hctx_seqt)
+                       break;
+               seqp = seqp->ccid2s_prev;
+       }
+
+       /* If there are at least 3 acknowledgements, anything unacknowledged
+        * below the last sequence number is considered lost
+        */
+       if (done == hctx->ccid2hctx_numdupack) {
+               struct ccid2_seq *last_acked = seqp;
+
+               /* check for lost packets */
+               while (1) {
+                       if (!seqp->ccid2s_acked) {
+                               loss = 1;
+                               ccid2_hc_tx_dec_pipe(sk);
+                       }
+                       if (seqp == hctx->ccid2hctx_seqt)
+                               break;
+                       seqp = seqp->ccid2s_prev;
+               }
+
+               hctx->ccid2hctx_seqt = last_acked;
+       }
+
+       /* trim acked packets in tail */
+       while (hctx->ccid2hctx_seqt != hctx->ccid2hctx_seqh) {
+               if (!hctx->ccid2hctx_seqt->ccid2s_acked)
+                       break;
+
+               hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next;
+       }
+
+       if (loss) {
+               /* XXX do bit shifts guarantee a 0 as the new bit? */
+               ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd >> 1);
+               hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd;
+               if (hctx->ccid2hctx_ssthresh < 2)
+                       hctx->ccid2hctx_ssthresh = 2;
+       }
+
+       ccid2_hc_tx_check_sanity(hctx);
+}
+
+static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
+{
+        struct ccid2_hc_tx_sock *hctx = ccid_priv(ccid);
+       int seqcount = ccid2_seq_len;
+       int i;
+
+       /* XXX init variables with proper values */
+       hctx->ccid2hctx_cwnd      = 1;
+       hctx->ccid2hctx_ssthresh  = 10;
+       hctx->ccid2hctx_numdupack = 3;
+
+       /* XXX init ~ to window size... */
+       hctx->ccid2hctx_seqbuf = kmalloc(sizeof(*hctx->ccid2hctx_seqbuf) *
+                                        seqcount, gfp_any());
+       if (hctx->ccid2hctx_seqbuf == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < (seqcount - 1); i++) {
+               hctx->ccid2hctx_seqbuf[i].ccid2s_next =
+                                       &hctx->ccid2hctx_seqbuf[i + 1];
+               hctx->ccid2hctx_seqbuf[i + 1].ccid2s_prev =
+                                       &hctx->ccid2hctx_seqbuf[i];
+       }
+       hctx->ccid2hctx_seqbuf[seqcount - 1].ccid2s_next =
+                                       hctx->ccid2hctx_seqbuf;
+       hctx->ccid2hctx_seqbuf->ccid2s_prev =
+                                       &hctx->ccid2hctx_seqbuf[seqcount - 1];
+
+       hctx->ccid2hctx_seqh     = hctx->ccid2hctx_seqbuf;
+       hctx->ccid2hctx_seqt     = hctx->ccid2hctx_seqh;
+       hctx->ccid2hctx_sent     = 0;
+       hctx->ccid2hctx_rto      = 3 * HZ;
+       hctx->ccid2hctx_srtt     = -1;
+       hctx->ccid2hctx_rttvar   = -1;
+       hctx->ccid2hctx_lastrtt  = 0;
+       hctx->ccid2hctx_rpdupack = -1;
+
+       hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire;
+       hctx->ccid2hctx_rtotimer.data     = (unsigned long)sk;
+       init_timer(&hctx->ccid2hctx_rtotimer);
+
+       ccid2_hc_tx_check_sanity(hctx);
+       return 0;
+}
+
+static void ccid2_hc_tx_exit(struct sock *sk)
+{
+        struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+       ccid2_hc_tx_kill_rto_timer(sk);
+       kfree(hctx->ccid2hctx_seqbuf);
+       hctx->ccid2hctx_seqbuf = NULL;
+}
+
+static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid2_hc_rx_sock *hcrx = ccid2_hc_rx_sk(sk);
+
+       switch (DCCP_SKB_CB(skb)->dccpd_type) {
+       case DCCP_PKT_DATA:
+       case DCCP_PKT_DATAACK:
+               hcrx->ccid2hcrx_data++;
+               if (hcrx->ccid2hcrx_data >= dp->dccps_r_ack_ratio) {
+                       dccp_send_ack(sk);
+                       hcrx->ccid2hcrx_data = 0;
+               }
+               break;
+       }
+}
+
+static struct ccid_operations ccid2 = {
+       .ccid_id                = 2,
+       .ccid_name              = "ccid2",
+       .ccid_owner             = THIS_MODULE,
+       .ccid_hc_tx_obj_size    = sizeof(struct ccid2_hc_tx_sock),
+       .ccid_hc_tx_init        = ccid2_hc_tx_init,
+       .ccid_hc_tx_exit        = ccid2_hc_tx_exit,
+       .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet,
+       .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent,
+       .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv,
+       .ccid_hc_rx_obj_size    = sizeof(struct ccid2_hc_rx_sock),
+       .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv,
+};
+
+module_param(ccid2_debug, int, 0444);
+MODULE_PARM_DESC(ccid2_debug, "Enable debug messages");
+
+static __init int ccid2_module_init(void)
+{
+       return ccid_register(&ccid2);
+}
+module_init(ccid2_module_init);
+
+static __exit void ccid2_module_exit(void)
+{
+       ccid_unregister(&ccid2);
+}
+module_exit(ccid2_module_exit);
+
+MODULE_AUTHOR("Andrea Bittau <a.bittau@cs.ucl.ac.uk>");
+MODULE_DESCRIPTION("DCCP TCP-Like (CCID2) CCID");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("net-dccp-ccid-2");
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
new file mode 100644 (file)
index 0000000..451a874
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *  net/dccp/ccids/ccid2.h
+ *
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _DCCP_CCID2_H_
+#define _DCCP_CCID2_H_
+
+#include <linux/dccp.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include "../ccid.h"
+
+struct sock;
+
+struct ccid2_seq {
+       u64                     ccid2s_seq;
+       unsigned long           ccid2s_sent;
+       int                     ccid2s_acked;
+       struct ccid2_seq        *ccid2s_prev;
+       struct ccid2_seq        *ccid2s_next;
+};
+
+/** struct ccid2_hc_tx_sock - CCID2 TX half connection
+ *
+ * @ccid2hctx_ssacks - ACKs recv in slow start
+ * @ccid2hctx_acks - ACKS recv in AI phase
+ * @ccid2hctx_sent - packets sent in this window
+ * @ccid2hctx_lastrtt -time RTT was last measured
+ * @ccid2hctx_arsent - packets sent [ack ratio]
+ * @ccid2hctx_ackloss - ack was lost in this win
+ * @ccid2hctx_rpseq - last consecutive seqno
+ * @ccid2hctx_rpdupack - dupacks since rpseq
+*/
+struct ccid2_hc_tx_sock {
+       int                     ccid2hctx_cwnd;
+       int                     ccid2hctx_ssacks;
+       int                     ccid2hctx_acks;
+       int                     ccid2hctx_ssthresh;
+       int                     ccid2hctx_pipe;
+       int                     ccid2hctx_numdupack;
+       struct ccid2_seq        *ccid2hctx_seqbuf;
+       struct ccid2_seq        *ccid2hctx_seqh;
+       struct ccid2_seq        *ccid2hctx_seqt;
+       long                    ccid2hctx_rto;
+       long                    ccid2hctx_srtt;
+       long                    ccid2hctx_rttvar;
+       int                     ccid2hctx_sent;
+       unsigned long           ccid2hctx_lastrtt;
+       struct timer_list       ccid2hctx_rtotimer;
+       unsigned long           ccid2hctx_arsent;
+       int                     ccid2hctx_ackloss;
+       u64                     ccid2hctx_rpseq;
+       int                     ccid2hctx_rpdupack;
+       int                     ccid2hctx_sendwait;
+};
+
+struct ccid2_hc_rx_sock {
+       int     ccid2hcrx_data;
+};
+
+static inline struct ccid2_hc_tx_sock *ccid2_hc_tx_sk(const struct sock *sk)
+{
+       return ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid);
+}
+
+static inline struct ccid2_hc_rx_sock *ccid2_hc_rx_sk(const struct sock *sk)
+{
+       return ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid);
+}
+#endif /* _DCCP_CCID2_H_ */
index 35d1d34..b4a51d0 100644 (file)
@@ -46,7 +46,7 @@
  * Reason for maths here is to avoid 32 bit overflow when a is big.
  * With this we get close to the limit.
  */
-static inline u32 usecs_div(const u32 a, const u32 b)
+static u32 usecs_div(const u32 a, const u32 b)
 {
        const u32 div = a < (UINT_MAX / (USEC_PER_SEC /    10)) ?    10 :
                        a < (UINT_MAX / (USEC_PER_SEC /    50)) ?    50 :
@@ -76,15 +76,6 @@ static struct dccp_tx_hist *ccid3_tx_hist;
 static struct dccp_rx_hist *ccid3_rx_hist;
 static struct dccp_li_hist *ccid3_li_hist;
 
-static int ccid3_init(struct sock *sk)
-{
-       return 0;
-}
-
-static void ccid3_exit(struct sock *sk)
-{
-}
-
 /* TFRC sender states */
 enum ccid3_hc_tx_states {
                TFRC_SSTATE_NO_SENT = 1,
@@ -107,8 +98,8 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
 }
 #endif
 
-static inline void ccid3_hc_tx_set_state(struct sock *sk,
-                                        enum ccid3_hc_tx_states state)
+static void ccid3_hc_tx_set_state(struct sock *sk,
+                                 enum ccid3_hc_tx_states state)
 {
        struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
        enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state;
@@ -316,8 +307,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk,
 
        switch (hctx->ccid3hctx_state) {
        case TFRC_SSTATE_NO_SENT:
-               hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
-               hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;
                sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
                               jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT));
                hctx->ccid3hctx_last_win_count   = 0;
@@ -585,16 +574,15 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
        }
 }
 
-static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
+static int ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
 {
        const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
        BUG_ON(hctx == NULL);
 
-       if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
-               return;
-
-        DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+       if (sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)
+               DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+       return 0;
 }
 
 static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
@@ -626,7 +614,7 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
                                       __FUNCTION__, dccp_role(sk), sk);
                        rc = -EINVAL;
                } else {
-                       opt_recv->ccid3or_loss_event_rate = ntohl(*(u32 *)value);
+                       opt_recv->ccid3or_loss_event_rate = ntohl(*(__be32 *)value);
                        ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n",
                                       dccp_role(sk), sk,
                                       opt_recv->ccid3or_loss_event_rate);
@@ -647,7 +635,7 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
                                       __FUNCTION__, dccp_role(sk), sk);
                        rc = -EINVAL;
                } else {
-                       opt_recv->ccid3or_receive_rate = ntohl(*(u32 *)value);
+                       opt_recv->ccid3or_receive_rate = ntohl(*(__be32 *)value);
                        ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n",
                                       dccp_role(sk), sk,
                                       opt_recv->ccid3or_receive_rate);
@@ -658,17 +646,10 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
        return rc;
 }
 
-static int ccid3_hc_tx_init(struct sock *sk)
+static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx;
-
-       dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx), gfp_any());
-       if (dp->dccps_hc_tx_ccid_private == NULL)
-               return -ENOMEM;
-
-       hctx = ccid3_hc_tx_sk(sk);
-       memset(hctx, 0, sizeof(*hctx));
+       struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid);
 
        if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE &&
            dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE)
@@ -681,6 +662,9 @@ static int ccid3_hc_tx_init(struct sock *sk)
        hctx->ccid3hctx_t_rto = USEC_PER_SEC;
        hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
        INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
+
+       hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
+       hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;
        init_timer(&hctx->ccid3hctx_no_feedback_timer);
 
        return 0;
@@ -688,7 +672,6 @@ static int ccid3_hc_tx_init(struct sock *sk)
 
 static void ccid3_hc_tx_exit(struct sock *sk)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
        struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
        BUG_ON(hctx == NULL);
@@ -698,9 +681,6 @@ static void ccid3_hc_tx_exit(struct sock *sk)
 
        /* Empty packet history */
        dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist);
-
-       kfree(dp->dccps_hc_tx_ccid_private);
-       dp->dccps_hc_tx_ccid_private = NULL;
 }
 
 /*
@@ -727,8 +707,8 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
 }
 #endif
 
-static inline void ccid3_hc_rx_set_state(struct sock *sk,
-                                        enum ccid3_hc_rx_states state)
+static void ccid3_hc_rx_set_state(struct sock *sk,
+                                 enum ccid3_hc_rx_states state)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state;
@@ -793,31 +773,35 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
        dccp_send_ack(sk);
 }
 
-static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
+static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
 {
        const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
-       u32 x_recv, pinv;
+       __be32 x_recv, pinv;
 
        BUG_ON(hcrx == NULL);
 
        if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
-               return;
+               return 0;
 
        DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter;
 
        if (dccp_packet_without_ack(skb))
-               return;
-               
-       if (hcrx->ccid3hcrx_elapsed_time != 0)
-               dccp_insert_option_elapsed_time(sk, skb,
-                                               hcrx->ccid3hcrx_elapsed_time);
-       dccp_insert_option_timestamp(sk, skb);
+               return 0;
+
        x_recv = htonl(hcrx->ccid3hcrx_x_recv);
        pinv   = htonl(hcrx->ccid3hcrx_pinv);
-       dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
-                          &pinv, sizeof(pinv));
-       dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
-                          &x_recv, sizeof(x_recv));
+
+       if ((hcrx->ccid3hcrx_elapsed_time != 0 &&
+            dccp_insert_option_elapsed_time(sk, skb,
+                                            hcrx->ccid3hcrx_elapsed_time)) ||
+           dccp_insert_option_timestamp(sk, skb) ||
+           dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
+                              &pinv, sizeof(pinv)) ||
+           dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
+                              &x_recv, sizeof(x_recv)))
+               return -1;
+
+       return 0;
 }
 
 /* calculate first loss interval
@@ -1047,20 +1031,13 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        }
 }
 
-static int ccid3_hc_rx_init(struct sock *sk)
+static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_rx_sock *hcrx;
+       struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid);
 
        ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
 
-       dp->dccps_hc_rx_ccid_private = kmalloc(sizeof(*hcrx), gfp_any());
-       if (dp->dccps_hc_rx_ccid_private == NULL)
-               return -ENOMEM;
-
-       hcrx = ccid3_hc_rx_sk(sk);
-       memset(hcrx, 0, sizeof(*hcrx));
-
        if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE &&
            dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE)
                hcrx->ccid3hcrx_s = dp->dccps_packet_size;
@@ -1079,7 +1056,6 @@ static int ccid3_hc_rx_init(struct sock *sk)
 static void ccid3_hc_rx_exit(struct sock *sk)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
-       struct dccp_sock *dp = dccp_sk(sk);
 
        BUG_ON(hcrx == NULL);
 
@@ -1090,9 +1066,6 @@ static void ccid3_hc_rx_exit(struct sock *sk)
 
        /* Empty loss interval history */
        dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist);
-
-       kfree(dp->dccps_hc_rx_ccid_private);
-       dp->dccps_hc_rx_ccid_private = NULL;
 }
 
 static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
@@ -1178,12 +1151,11 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
        return 0;
 }
 
-static struct ccid ccid3 = {
+static struct ccid_operations ccid3 = {
        .ccid_id                   = 3,
        .ccid_name                 = "ccid3",
        .ccid_owner                = THIS_MODULE,
-       .ccid_init                 = ccid3_init,
-       .ccid_exit                 = ccid3_exit,
+       .ccid_hc_tx_obj_size       = sizeof(struct ccid3_hc_tx_sock),
        .ccid_hc_tx_init           = ccid3_hc_tx_init,
        .ccid_hc_tx_exit           = ccid3_hc_tx_exit,
        .ccid_hc_tx_send_packet    = ccid3_hc_tx_send_packet,
@@ -1191,6 +1163,7 @@ static struct ccid ccid3 = {
        .ccid_hc_tx_packet_recv    = ccid3_hc_tx_packet_recv,
        .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options,
        .ccid_hc_tx_parse_options  = ccid3_hc_tx_parse_options,
+       .ccid_hc_rx_obj_size       = sizeof(struct ccid3_hc_rx_sock),
        .ccid_hc_rx_init           = ccid3_hc_rx_init,
        .ccid_hc_rx_exit           = ccid3_hc_rx_exit,
        .ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options,
@@ -1241,15 +1214,6 @@ module_init(ccid3_module_init);
 
 static __exit void ccid3_module_exit(void)
 {
-#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
-       /*
-        * Hack to use while developing, so that we get rid of the control
-        * sock, that is what keeps a refcount on dccp.ko -acme
-        */
-       extern void dccp_ctl_sock_exit(void);
-
-       dccp_ctl_sock_exit();
-#endif
        ccid_unregister(&ccid3);
 
        if (ccid3_tx_hist != NULL) {
index 0bde458..f18b96d 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/time.h>
 #include <linux/types.h>
 #include <linux/tfrc.h>
+#include "../ccid.h"
 
 #define TFRC_MIN_PACKET_SIZE      16
 #define TFRC_STD_PACKET_SIZE     256
@@ -135,12 +136,12 @@ struct ccid3_hc_rx_sock {
 
 static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk)
 {
-    return dccp_sk(sk)->dccps_hc_tx_ccid_private;
+    return ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid);
 }
 
 static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk)
 {
-    return dccp_sk(sk)->dccps_hc_rx_ccid_private;
+    return ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid);
 }
 
 #endif /* _DCCP_CCID3_H_ */
index 93f26dd..1fe5091 100644 (file)
@@ -59,8 +59,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
 
 #define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */
 
-extern struct proto dccp_prot;
-
 /* is seq1 < seq2 ? */
 static inline int before48(const u64 seq1, const u64 seq2)
 {
@@ -120,7 +118,6 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics);
 
 extern int  dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb);
 
-extern int dccp_send_response(struct sock *sk);
 extern void dccp_send_ack(struct sock *sk);
 extern void dccp_send_delayed_ack(struct sock *sk);
 extern void dccp_send_sync(struct sock *sk, const u64 seq,
@@ -140,53 +137,8 @@ extern unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu);
 extern const char *dccp_packet_name(const int type);
 extern const char *dccp_state_name(const int state);
 
-static inline void dccp_set_state(struct sock *sk, const int state)
-{
-       const int oldstate = sk->sk_state;
-
-       dccp_pr_debug("%s(%p) %-10.10s -> %s\n",
-                     dccp_role(sk), sk,
-                     dccp_state_name(oldstate), dccp_state_name(state));
-       WARN_ON(state == oldstate);
-
-       switch (state) {
-       case DCCP_OPEN:
-               if (oldstate != DCCP_OPEN)
-                       DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
-               break;
-
-       case DCCP_CLOSED:
-               if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN)
-                       DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
-
-               sk->sk_prot->unhash(sk);
-               if (inet_csk(sk)->icsk_bind_hash != NULL &&
-                   !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
-                       inet_put_port(&dccp_hashinfo, sk);
-               /* fall through */
-       default:
-               if (oldstate == DCCP_OPEN)
-                       DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
-       }
-
-       /* Change state AFTER socket is unhashed to avoid closed
-        * socket sitting in hash tables.
-        */
-       sk->sk_state = state;
-}
-
-static inline void dccp_done(struct sock *sk)
-{
-       dccp_set_state(sk, DCCP_CLOSED);
-       dccp_clear_xmit_timers(sk);
-
-       sk->sk_shutdown = SHUTDOWN_MASK;
-
-       if (!sock_flag(sk, SOCK_DEAD))
-               sk->sk_state_change(sk);
-       else
-               inet_csk_destroy_sock(sk);
-}
+extern void dccp_set_state(struct sock *sk, const int state);
+extern void dccp_done(struct sock *sk);
 
 static inline void dccp_openreq_init(struct request_sock *req,
                                     struct dccp_sock *dp,
@@ -209,10 +161,6 @@ extern struct sock *dccp_create_openreq_child(struct sock *sk,
 
 extern int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb);
 
-extern void dccp_v4_err(struct sk_buff *skb, u32);
-
-extern int dccp_v4_rcv(struct sk_buff *skb);
-
 extern struct sock *dccp_v4_request_recv_sock(struct sock *sk,
                                              struct sk_buff *skb,
                                              struct request_sock *req,
@@ -228,24 +176,30 @@ extern int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 extern int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                const struct dccp_hdr *dh, const unsigned len);
 
-extern int dccp_v4_init_sock(struct sock *sk);
-extern int dccp_v4_destroy_sock(struct sock *sk);
+extern int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized);
+extern int dccp_destroy_sock(struct sock *sk);
 
 extern void            dccp_close(struct sock *sk, long timeout);
 extern struct sk_buff  *dccp_make_response(struct sock *sk,
                                            struct dst_entry *dst,
                                            struct request_sock *req);
-extern struct sk_buff  *dccp_make_reset(struct sock *sk,
-                                        struct dst_entry *dst,
-                                        enum dccp_reset_codes code);
 
 extern int        dccp_connect(struct sock *sk);
 extern int        dccp_disconnect(struct sock *sk, int flags);
+extern void       dccp_hash(struct sock *sk);
 extern void       dccp_unhash(struct sock *sk);
 extern int        dccp_getsockopt(struct sock *sk, int level, int optname,
                                   char __user *optval, int __user *optlen);
 extern int        dccp_setsockopt(struct sock *sk, int level, int optname,
                                   char __user *optval, int optlen);
+#ifdef CONFIG_COMPAT
+extern int        compat_dccp_getsockopt(struct sock *sk,
+                               int level, int optname,
+                               char __user *optval, int __user *optlen);
+extern int        compat_dccp_setsockopt(struct sock *sk,
+                               int level, int optname,
+                               char __user *optval, int optlen);
+#endif
 extern int        dccp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern int        dccp_sendmsg(struct kiocb *iocb, struct sock *sk,
                                struct msghdr *msg, size_t size);
@@ -262,15 +216,14 @@ extern int           dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
                                   int addr_len);
 
 extern int        dccp_v4_checksum(const struct sk_buff *skb,
-                                   const u32 saddr, const u32 daddr);
+                                   const __be32 saddr, const __be32 daddr);
 
-extern int        dccp_v4_send_reset(struct sock *sk,
-                                     enum dccp_reset_codes code);
+extern int        dccp_send_reset(struct sock *sk, enum dccp_reset_codes code);
 extern void       dccp_send_close(struct sock *sk, const int active);
 extern int        dccp_invalid_packet(struct sk_buff *skb);
 
 static inline int dccp_bad_service_code(const struct sock *sk,
-                                       const __u32 service)
+                                       const __be32 service)
 {
        const struct dccp_sock *dp = dccp_sk(sk);
 
@@ -334,41 +287,29 @@ static inline void dccp_hdr_set_seq(struct dccp_hdr *dh, const u64 gss)
 {
        struct dccp_hdr_ext *dhx = (struct dccp_hdr_ext *)((void *)dh +
                                                           sizeof(*dh));
-
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       dh->dccph_seq      = htonl((gss >> 32)) >> 8;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       dh->dccph_seq      = htonl((gss >> 32));
-#else
-#error  "Adjust your <asm/byteorder.h> defines"
-#endif
+       dh->dccph_seq2 = 0;
+       dh->dccph_seq = htons((gss >> 32) & 0xfffff);
        dhx->dccph_seq_low = htonl(gss & 0xffffffff);
 }
 
 static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack,
                                    const u64 gsr)
 {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       dhack->dccph_ack_nr_high = htonl((gsr >> 32)) >> 8;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       dhack->dccph_ack_nr_high = htonl((gsr >> 32));
-#else
-#error  "Adjust your <asm/byteorder.h> defines"
-#endif
+       dhack->dccph_reserved1 = 0;
+       dhack->dccph_ack_nr_high = htons(gsr >> 32);
        dhack->dccph_ack_nr_low  = htonl(gsr & 0xffffffff);
 }
 
 static inline void dccp_update_gsr(struct sock *sk, u64 seq)
 {
        struct dccp_sock *dp = dccp_sk(sk);
+       const struct dccp_minisock *dmsk = dccp_msk(sk);
 
        dp->dccps_gsr = seq;
        dccp_set_seqno(&dp->dccps_swl,
-                      (dp->dccps_gsr + 1 -
-                       (dp->dccps_options.dccpo_sequence_window / 4)));
+                      dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4));
        dccp_set_seqno(&dp->dccps_swh,
-                      (dp->dccps_gsr +
-                       (3 * dp->dccps_options.dccpo_sequence_window) / 4));
+                      dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4);
 }
 
 static inline void dccp_update_gss(struct sock *sk, u64 seq)
@@ -378,7 +319,7 @@ static inline void dccp_update_gss(struct sock *sk, u64 seq)
        dp->dccps_awh = dp->dccps_gss = seq;
        dccp_set_seqno(&dp->dccps_awl,
                       (dp->dccps_gss -
-                       dp->dccps_options.dccpo_sequence_window + 1));
+                       dccp_msk(sk)->dccpms_sequence_window + 1));
 }
                                
 static inline int dccp_ack_pending(const struct sock *sk)
@@ -386,24 +327,22 @@ static inline int dccp_ack_pending(const struct sock *sk)
        const struct dccp_sock *dp = dccp_sk(sk);
        return dp->dccps_timestamp_echo != 0 ||
 #ifdef CONFIG_IP_DCCP_ACKVEC
-              (dp->dccps_options.dccpo_send_ack_vector &&
+              (dccp_msk(sk)->dccpms_send_ack_vector &&
                dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
 #endif
               inet_csk_ack_scheduled(sk);
 }
 
-extern void dccp_insert_options(struct sock *sk, struct sk_buff *skb);
-extern void dccp_insert_option_elapsed_time(struct sock *sk,
+extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
+extern int dccp_insert_option_elapsed_time(struct sock *sk,
                                            struct sk_buff *skb,
                                            u32 elapsed_time);
-extern void dccp_insert_option_timestamp(struct sock *sk,
+extern int dccp_insert_option_timestamp(struct sock *sk,
                                         struct sk_buff *skb);
-extern void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
+extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
                               unsigned char option,
                               const void *value, unsigned char len);
 
-extern struct socket *dccp_ctl_socket;
-
 extern void dccp_timestamp(const struct sock *sk, struct timeval *tv);
 
 static inline suseconds_t timeval_usecs(const struct timeval *tv)
@@ -444,4 +383,18 @@ static inline void timeval_sub_usecs(struct timeval *tv,
        }
 }
 
+#ifdef CONFIG_SYSCTL
+extern int dccp_sysctl_init(void);
+extern void dccp_sysctl_exit(void);
+#else
+static inline int dccp_sysctl_init(void)
+{
+       return 0;
+}
+
+static inline void dccp_sysctl_exit(void)
+{
+}
+#endif
+
 #endif /* _DCCP_H */
index 3f78c00..0f25dc3 100644 (file)
@@ -30,7 +30,7 @@ static void dccp_get_info(struct sock *sk, struct tcp_info *info)
        info->tcpi_backoff      = icsk->icsk_backoff;
        info->tcpi_pmtu         = icsk->icsk_pmtu_cookie;
 
-       if (dp->dccps_options.dccpo_send_ack_vector)
+       if (dccp_msk(sk)->dccpms_send_ack_vector)
                info->tcpi_options |= TCPI_OPT_SACK;
 
        ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info);
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
new file mode 100644 (file)
index 0000000..e3dd30d
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ *  net/dccp/feat.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include "dccp.h"
+#include "ccid.h"
+#include "feat.h"
+
+#define DCCP_FEAT_SP_NOAGREE (-123)
+
+int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
+                    u8 *val, u8 len, gfp_t gfp)
+{
+       struct dccp_opt_pend *opt;
+
+       dccp_pr_debug("feat change type=%d feat=%d\n", type, feature);
+
+       /* XXX sanity check feat change request */
+
+       /* check if that feature is already being negotiated */
+       list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
+               /* ok we found a negotiation for this option already */
+               if (opt->dccpop_feat == feature && opt->dccpop_type == type) {
+                       dccp_pr_debug("Replacing old\n");
+                       /* replace */
+                       BUG_ON(opt->dccpop_val == NULL);
+                       kfree(opt->dccpop_val);
+                       opt->dccpop_val  = val;
+                       opt->dccpop_len  = len;
+                       opt->dccpop_conf = 0;
+                       return 0;
+               }
+       }
+
+       /* negotiation for a new feature */
+       opt = kmalloc(sizeof(*opt), gfp);
+       if (opt == NULL)
+               return -ENOMEM;
+
+       opt->dccpop_type = type;
+       opt->dccpop_feat = feature;
+       opt->dccpop_len  = len;
+       opt->dccpop_val  = val;
+       opt->dccpop_conf = 0;
+       opt->dccpop_sc   = NULL;
+
+       BUG_ON(opt->dccpop_val == NULL);
+
+       list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_change);
+
+static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+       /* figure out if we are changing our CCID or the peer's */
+       const int rx = type == DCCPO_CHANGE_R;
+       const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid;
+       struct ccid *new_ccid;
+
+       /* Check if nothing is being changed. */
+       if (ccid_nr == new_ccid_nr)
+               return 0;
+
+       new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);
+       if (new_ccid == NULL)
+               return -ENOMEM;
+
+       if (rx) {
+               ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+               dp->dccps_hc_rx_ccid = new_ccid;
+               dmsk->dccpms_rx_ccid = new_ccid_nr;
+       } else {
+               ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+               dp->dccps_hc_tx_ccid = new_ccid;
+               dmsk->dccpms_tx_ccid = new_ccid_nr;
+       }
+
+       return 0;
+}
+
+/* XXX taking only u8 vals */
+static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
+{
+       dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val);
+
+       switch (feat) {
+       case DCCPF_CCID:
+               return dccp_feat_update_ccid(sk, type, val);
+       default:
+               dccp_pr_debug("IMPLEMENT changing [%d] feat %d to %d\n",
+                             type, feat, val);
+               break;
+       }
+       return 0;
+}
+
+static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
+                              u8 *rpref, u8 rlen)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       u8 *spref, slen, *res = NULL;
+       int i, j, rc, agree = 1;
+
+       BUG_ON(rpref == NULL);
+
+       /* check if we are the black sheep */
+       if (dp->dccps_role == DCCP_ROLE_CLIENT) {
+               spref = rpref;
+               slen  = rlen;
+               rpref = opt->dccpop_val;
+               rlen  = opt->dccpop_len;
+       } else {
+               spref = opt->dccpop_val;
+               slen  = opt->dccpop_len;
+       }
+       /*
+        * Now we have server preference list in spref and client preference in
+        * rpref
+        */
+       BUG_ON(spref == NULL);
+       BUG_ON(rpref == NULL);
+
+       /* FIXME sanity check vals */
+
+       /* Are values in any order?  XXX Lame "algorithm" here */
+       /* XXX assume values are 1 byte */
+       for (i = 0; i < slen; i++) {
+               for (j = 0; j < rlen; j++) {
+                       if (spref[i] == rpref[j]) {
+                               res = &spref[i];
+                               break;
+                       }
+               }
+               if (res)
+                       break;
+       }
+
+       /* we didn't agree on anything */
+       if (res == NULL) {
+               /* confirm previous value */
+               switch (opt->dccpop_feat) {
+               case DCCPF_CCID:
+                       /* XXX did i get this right? =P */
+                       if (opt->dccpop_type == DCCPO_CHANGE_L)
+                               res = &dccp_msk(sk)->dccpms_tx_ccid;
+                       else
+                               res = &dccp_msk(sk)->dccpms_rx_ccid;
+                       break;
+
+               default:
+                       WARN_ON(1); /* XXX implement res */
+                       return -EFAULT;
+               }
+
+               dccp_pr_debug("Don't agree... reconfirming %d\n", *res);
+               agree = 0; /* this is used for mandatory options... */
+       }
+
+       /* need to put result and our preference list */
+       /* XXX assume 1 byte vals */
+       rlen = 1 + opt->dccpop_len;
+       rpref = kmalloc(rlen, GFP_ATOMIC);
+       if (rpref == NULL)
+               return -ENOMEM;
+
+       *rpref = *res;
+       memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len);
+
+       /* put it in the "confirm queue" */
+       if (opt->dccpop_sc == NULL) {
+               opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);
+               if (opt->dccpop_sc == NULL) {
+                       kfree(rpref);
+                       return -ENOMEM;
+               }
+       } else {
+               /* recycle the confirm slot */
+               BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
+               kfree(opt->dccpop_sc->dccpoc_val);
+               dccp_pr_debug("recycling confirm slot\n");
+       }
+       memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc));
+
+       opt->dccpop_sc->dccpoc_val = rpref;
+       opt->dccpop_sc->dccpoc_len = rlen;
+
+       /* update the option on our side [we are about to send the confirm] */
+       rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res);
+       if (rc) {
+               kfree(opt->dccpop_sc->dccpoc_val);
+               kfree(opt->dccpop_sc);
+               opt->dccpop_sc = 0;
+               return rc;
+       }
+
+       dccp_pr_debug("Will confirm %d\n", *rpref);
+
+       /* say we want to change to X but we just got a confirm X, suppress our
+        * change
+        */
+       if (!opt->dccpop_conf) {
+               if (*opt->dccpop_val == *res)
+                       opt->dccpop_conf = 1;
+               dccp_pr_debug("won't ask for change of same feature\n");
+       }
+
+       return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */
+}
+
+static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
+{
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+       struct dccp_opt_pend *opt;
+       int rc = 1;
+       u8 t;
+
+       /*
+        * We received a CHANGE.  We gotta match it against our own preference
+        * list.  If we got a CHANGE_R it means it's a change for us, so we need
+        * to compare our CHANGE_L list.
+        */
+       if (type == DCCPO_CHANGE_L)
+               t = DCCPO_CHANGE_R;
+       else
+               t = DCCPO_CHANGE_L;
+
+       /* find our preference list for this feature */
+       list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
+               if (opt->dccpop_type != t || opt->dccpop_feat != feature)
+                       continue;
+
+               /* find the winner from the two preference lists */
+               rc = dccp_feat_reconcile(sk, opt, val, len);
+               break;
+       }
+
+       /* We didn't deal with the change.  This can happen if we have no
+        * preference list for the feature.  In fact, it just shouldn't
+        * happen---if we understand a feature, we should have a preference list
+        * with at least the default value.
+        */
+       BUG_ON(rc == 1);
+
+       return rc;
+}
+
+static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
+{
+       struct dccp_opt_pend *opt;
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+       u8 *copy;
+       int rc;
+
+       /* NN features must be change L */
+       if (type == DCCPO_CHANGE_R) {
+               dccp_pr_debug("received CHANGE_R %d for NN feat %d\n",
+                             type, feature);
+               return -EFAULT;
+       }
+
+       /* XXX sanity check opt val */
+
+       /* copy option so we can confirm it */
+       opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
+       if (opt == NULL)
+               return -ENOMEM;
+
+       copy = kmalloc(len, GFP_ATOMIC);
+       if (copy == NULL) {
+               kfree(opt);
+               return -ENOMEM;
+       }
+       memcpy(copy, val, len);
+
+       opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */
+       opt->dccpop_feat = feature;
+       opt->dccpop_val  = copy;
+       opt->dccpop_len  = len;
+
+       /* change feature */
+       rc = dccp_feat_update(sk, type, feature, *val);
+       if (rc) {
+               kfree(opt->dccpop_val);
+               kfree(opt);
+               return rc;
+       }
+
+       dccp_pr_debug("Confirming NN feature %d (val=%d)\n", feature, *copy);
+       list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
+
+       return 0;
+}
+
+static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
+                                   u8 type, u8 feature)
+{
+       /* XXX check if other confirms for that are queued and recycle slot */
+       struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
+
+       if (opt == NULL) {
+               /* XXX what do we do?  Ignoring should be fine.  It's a change
+                * after all =P
+                */
+               return;
+       }
+
+       opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R :
+                                                   DCCPO_CONFIRM_L;
+       opt->dccpop_feat = feature;
+       opt->dccpop_val  = 0;
+       opt->dccpop_len  = 0;
+
+       /* change feature */
+       dccp_pr_debug("Empty confirm feature %d type %d\n", feature, type);
+       list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
+}
+
+static void dccp_feat_flush_confirm(struct sock *sk)
+{
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+       /* Check if there is anything to confirm in the first place */
+       int yes = !list_empty(&dmsk->dccpms_conf);
+
+       if (!yes) {
+               struct dccp_opt_pend *opt;
+
+               list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
+                       if (opt->dccpop_conf) {
+                               yes = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (!yes)
+               return;
+
+       /* OK there is something to confirm... */
+       /* XXX check if packet is in flight?  Send delayed ack?? */
+       if (sk->sk_state == DCCP_OPEN)
+               dccp_send_ack(sk);
+}
+
+int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
+{
+       int rc;
+
+       dccp_pr_debug("got feat change type=%d feat=%d\n", type, feature);
+
+       /* figure out if it's SP or NN feature */
+       switch (feature) {
+       /* deal with SP features */
+       case DCCPF_CCID:
+               rc = dccp_feat_sp(sk, type, feature, val, len);
+               break;
+
+       /* deal with NN features */
+       case DCCPF_ACK_RATIO:
+               rc = dccp_feat_nn(sk, type, feature, val, len);
+               break;
+
+       /* XXX implement other features */
+       default:
+               rc = -EFAULT;
+               break;
+       }
+
+       /* check if there were problems changing features */
+       if (rc) {
+               /* If we don't agree on SP, we sent a confirm for old value.
+                * However we propagate rc to caller in case option was
+                * mandatory
+                */
+               if (rc != DCCP_FEAT_SP_NOAGREE)
+                       dccp_feat_empty_confirm(dccp_msk(sk), type, feature);
+       }
+
+       /* generate the confirm [if required] */
+       dccp_feat_flush_confirm(sk);
+
+       return rc;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
+
+int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
+                          u8 *val, u8 len)
+{
+       u8 t;
+       struct dccp_opt_pend *opt;
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+       int rc = 1;
+       int all_confirmed = 1;
+
+       dccp_pr_debug("got feat confirm type=%d feat=%d\n", type, feature);
+
+       /* XXX sanity check type & feat */
+
+       /* locate our change request */
+       t = type == DCCPO_CONFIRM_L ? DCCPO_CHANGE_R : DCCPO_CHANGE_L;
+
+       list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
+               if (!opt->dccpop_conf && opt->dccpop_type == t &&
+                   opt->dccpop_feat == feature) {
+                       /* we found it */
+                       /* XXX do sanity check */
+
+                       opt->dccpop_conf = 1;
+
+                       /* We got a confirmation---change the option */
+                       dccp_feat_update(sk, opt->dccpop_type,
+                                        opt->dccpop_feat, *val);
+
+                       dccp_pr_debug("feat %d type %d confirmed %d\n",
+                                     feature, type, *val);
+                       rc = 0;
+                       break;
+               }
+
+               if (!opt->dccpop_conf)
+                       all_confirmed = 0;
+       }
+
+       /* fix re-transmit timer */
+       /* XXX gotta make sure that no option negotiation occurs during
+        * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
+        * on.  if all options are confirmed it might kill timer which should
+        * remain alive until close is received.
+        */
+       if (all_confirmed) {
+               dccp_pr_debug("clear feat negotiation timer %p\n", sk);
+               inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
+       }
+
+       if (rc)
+               dccp_pr_debug("feat %d type %d never requested\n",
+                             feature, type);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
+
+void dccp_feat_clean(struct dccp_minisock *dmsk)
+{
+       struct dccp_opt_pend *opt, *next;
+
+       list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending,
+                                dccpop_node) {
+                BUG_ON(opt->dccpop_val == NULL);
+                kfree(opt->dccpop_val);
+
+               if (opt->dccpop_sc != NULL) {
+                       BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
+                       kfree(opt->dccpop_sc->dccpoc_val);
+                       kfree(opt->dccpop_sc);
+               }
+
+                kfree(opt);
+        }
+       INIT_LIST_HEAD(&dmsk->dccpms_pending);
+
+       list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
+               BUG_ON(opt == NULL);
+               if (opt->dccpop_val != NULL)
+                       kfree(opt->dccpop_val);
+               kfree(opt);
+       }
+       INIT_LIST_HEAD(&dmsk->dccpms_conf);
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_clean);
+
+/* this is to be called only when a listening sock creates its child.  It is
+ * assumed by the function---the confirm is not duplicated, but rather it is
+ * "passed on".
+ */
+int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
+{
+       struct dccp_minisock *olddmsk = dccp_msk(oldsk);
+       struct dccp_minisock *newdmsk = dccp_msk(newsk);
+       struct dccp_opt_pend *opt;
+       int rc = 0;
+
+       INIT_LIST_HEAD(&newdmsk->dccpms_pending);
+       INIT_LIST_HEAD(&newdmsk->dccpms_conf);
+
+       list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) {
+               struct dccp_opt_pend *newopt;
+               /* copy the value of the option */
+               u8 *val = kmalloc(opt->dccpop_len, GFP_ATOMIC);
+
+               if (val == NULL)
+                       goto out_clean;
+               memcpy(val, opt->dccpop_val, opt->dccpop_len);
+
+               newopt = kmalloc(sizeof(*newopt), GFP_ATOMIC);
+               if (newopt == NULL) {
+                       kfree(val);
+                       goto out_clean;
+               }
+
+               /* insert the option */
+               memcpy(newopt, opt, sizeof(*newopt));
+               newopt->dccpop_val = val;
+               list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending);
+
+               /* XXX what happens with backlogs and multiple connections at
+                * once...
+                */
+               /* the master socket no longer needs to worry about confirms */
+               opt->dccpop_sc = 0; /* it's not a memleak---new socket has it */
+
+               /* reset state for a new socket */
+               opt->dccpop_conf = 0;
+       }
+
+       /* XXX not doing anything about the conf queue */
+
+out:
+       return rc;
+
+out_clean:
+       dccp_feat_clean(newdmsk);
+       rc = -ENOMEM;
+       goto out;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_clone);
+
+static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
+                           u8 *val, u8 len)
+{
+       int rc = -ENOMEM;
+       u8 *copy = kmalloc(len, GFP_KERNEL);
+
+       if (copy != NULL) {
+               memcpy(copy, val, len);
+               rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
+               if (rc)
+                       kfree(copy);
+       }
+       return rc;
+}
+
+int dccp_feat_init(struct dccp_minisock *dmsk)
+{
+       int rc;
+
+       INIT_LIST_HEAD(&dmsk->dccpms_pending);
+       INIT_LIST_HEAD(&dmsk->dccpms_conf);
+
+       /* CCID L */
+       rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
+                             &dmsk->dccpms_tx_ccid, 1);
+       if (rc)
+               goto out;
+
+       /* CCID R */
+       rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
+                             &dmsk->dccpms_rx_ccid, 1);
+       if (rc)
+               goto out;
+
+       /* Ack ratio */
+       rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
+                             &dmsk->dccpms_ack_ratio, 1);
+out:
+       return rc;
+}
+
+EXPORT_SYMBOL_GPL(dccp_feat_init);
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
new file mode 100644 (file)
index 0000000..6048373
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _DCCP_FEAT_H
+#define _DCCP_FEAT_H
+/*
+ *  net/dccp/feat.h
+ *
+ *  An implementation of the DCCP protocol
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *     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.
+ */
+
+#include <linux/types.h>
+
+struct sock;
+struct dccp_minisock;
+
+extern int  dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
+                            u8 *val, u8 len, gfp_t gfp);
+extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
+                                 u8 *val, u8 len);
+extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
+                                  u8 *val, u8 len);
+extern void dccp_feat_clean(struct dccp_minisock *dmsk);
+extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_init(struct dccp_minisock *dmsk);
+
+#endif /* _DCCP_FEAT_H */
index b6cba72..bfc5366 100644 (file)
@@ -32,7 +32,7 @@ static void dccp_fin(struct sock *sk, struct sk_buff *skb)
 
 static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
 {
-       dccp_v4_send_reset(sk, DCCP_RESET_CODE_CLOSED);
+       dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
        dccp_fin(sk, skb);
        dccp_set_state(sk, DCCP_CLOSED);
        sk_wake_async(sk, 1, POLL_HUP);
@@ -56,11 +56,11 @@ static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
        dccp_send_close(sk, 0);
 }
 
-static inline void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
+static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
 
-       if (dp->dccps_options.dccpo_send_ack_vector)
+       if (dccp_msk(sk)->dccpms_send_ack_vector)
                dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk,
                                            DCCP_SKB_CB(skb)->dccpd_ack_seq);
 }
@@ -151,9 +151,8 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
-static inline int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
-                                        const struct dccp_hdr *dh,
-                                        const unsigned len)
+static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
+                                 const struct dccp_hdr *dh, const unsigned len)
 {
        struct dccp_sock *dp = dccp_sk(sk);
 
@@ -247,7 +246,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
        if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
                dccp_event_ack_recv(sk, skb);
 
-       if (dp->dccps_options.dccpo_send_ack_vector &&
+       if (dccp_msk(sk)->dccpms_send_ack_vector &&
            dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
                            DCCP_SKB_CB(skb)->dccpd_seq,
                            DCCP_ACKVEC_STATE_RECEIVED))
@@ -300,7 +299,10 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
                        goto out_invalid_packet;
                }
 
-                if (dp->dccps_options.dccpo_send_ack_vector &&
+               if (dccp_parse_options(sk, skb))
+                       goto out_invalid_packet;
+
+                if (dccp_msk(sk)->dccpms_send_ack_vector &&
                     dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
                                     DCCP_SKB_CB(skb)->dccpd_seq,
                                     DCCP_ACKVEC_STATE_RECEIVED))
@@ -321,14 +323,6 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
                dccp_set_seqno(&dp->dccps_swl,
                               max48(dp->dccps_swl, dp->dccps_isr));
 
-               if (ccid_hc_rx_init(dp->dccps_hc_rx_ccid, sk) != 0 ||
-                   ccid_hc_tx_init(dp->dccps_hc_tx_ccid, sk) != 0) {
-                       ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
-                       ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
-                       /* FIXME: send appropriate RESET code */
-                       goto out_invalid_packet;
-               }
-
                dccp_sync_mss(sk, icsk->icsk_pmtu_cookie);
 
                /*
@@ -492,7 +486,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
                        dccp_event_ack_recv(sk, skb);
 
-               if (dp->dccps_options.dccpo_send_ack_vector &&
+               if (dccp_msk(sk)->dccpms_send_ack_vector &&
                    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
                                    DCCP_SKB_CB(skb)->dccpd_seq,
                                    DCCP_ACKVEC_STATE_RECEIVED))
index dc0487b..2904799 100644 (file)
 #include <linux/random.h>
 
 #include <net/icmp.h>
+#include <net/inet_common.h>
 #include <net/inet_hashtables.h>
 #include <net/inet_sock.h>
+#include <net/protocol.h>
 #include <net/sock.h>
 #include <net/timewait_sock.h>
 #include <net/tcp_states.h>
 #include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
-struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
-       .lhash_lock     = RW_LOCK_UNLOCKED,
-       .lhash_users    = ATOMIC_INIT(0),
-       .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
-};
-
-EXPORT_SYMBOL_GPL(dccp_hashinfo);
+/*
+ * This is the global socket data structure used for responding to
+ * the Out-of-the-blue (OOTB) packets. A control sock will be created
+ * for this socket at the initialization time.
+ */
+static struct socket *dccp_v4_ctl_socket;
 
 static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
 {
@@ -43,18 +45,6 @@ static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
                                 inet_csk_bind_conflict);
 }
 
-static void dccp_v4_hash(struct sock *sk)
-{
-       inet_hash(&dccp_hashinfo, sk);
-}
-
-void dccp_unhash(struct sock *sk)
-{
-       inet_unhash(&dccp_hashinfo, sk);
-}
-
-EXPORT_SYMBOL_GPL(dccp_unhash);
-
 int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct inet_sock *inet = inet_sk(sk);
@@ -207,11 +197,12 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk,
        } /* else let the usual retransmit timer handle it */
 }
 
-static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb)
+static void dccp_v4_reqsk_send_ack(struct sk_buff *rxskb,
+                                  struct request_sock *req)
 {
        int err;
        struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
-       const int dccp_hdr_ack_len = sizeof(struct dccp_hdr) +
+       const u32 dccp_hdr_ack_len = sizeof(struct dccp_hdr) +
                                     sizeof(struct dccp_hdr_ext) +
                                     sizeof(struct dccp_hdr_ack_bits);
        struct sk_buff *skb;
@@ -219,12 +210,12 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb)
        if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
                return;
 
-       skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC);
+       skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header, GFP_ATOMIC);
        if (skb == NULL)
                return;
 
        /* Reserve space for headers. */
-       skb_reserve(skb, MAX_DCCP_HEADER);
+       skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header);
 
        skb->dst = dst_clone(rxskb->dst);
 
@@ -243,11 +234,11 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb)
        dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
                         DCCP_SKB_CB(rxskb)->dccpd_seq);
 
-       bh_lock_sock(dccp_ctl_socket->sk);
-       err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
+       bh_lock_sock(dccp_v4_ctl_socket->sk);
+       err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk,
                                    rxskb->nh.iph->daddr,
                                    rxskb->nh.iph->saddr, NULL);
-       bh_unlock_sock(dccp_ctl_socket->sk);
+       bh_unlock_sock(dccp_v4_ctl_socket->sk);
 
        if (err == NET_XMIT_CN || err == 0) {
                DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
@@ -255,12 +246,6 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb)
        }
 }
 
-static void dccp_v4_reqsk_send_ack(struct sk_buff *skb,
-                                  struct request_sock *req)
-{
-       dccp_v4_ctl_send_ack(skb);
-}
-
 static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
                                 struct dst_entry *dst)
 {
@@ -275,7 +260,10 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
        skb = dccp_make_response(sk, dst, req);
        if (skb != NULL) {
                const struct inet_request_sock *ireq = inet_rsk(req);
+               struct dccp_hdr *dh = dccp_hdr(skb);
 
+               dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr,
+                                                     ireq->rmt_addr);
                memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
                err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
                                            ireq->rmt_addr,
@@ -301,7 +289,7 @@ out:
  * check at all. A more general error queue to queue errors for later handling
  * is probably better.
  */
-void dccp_v4_err(struct sk_buff *skb, u32 info)
+static void dccp_v4_err(struct sk_buff *skb, u32 info)
 {
        const struct iphdr *iph = (struct iphdr *)skb->data;
        const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data +
@@ -456,32 +444,6 @@ void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
 
 EXPORT_SYMBOL_GPL(dccp_v4_send_check);
 
-int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code)
-{
-       struct sk_buff *skb;
-       /*
-        * FIXME: what if rebuild_header fails?
-        * Should we be doing a rebuild_header here?
-        */
-       int err = inet_sk_rebuild_header(sk);
-
-       if (err != 0)
-               return err;
-
-       skb = dccp_make_reset(sk, sk->sk_dst_cache, code);
-       if (skb != NULL) {
-               const struct inet_sock *inet = inet_sk(sk);
-
-               memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
-               err = ip_build_and_send_pkt(skb, sk,
-                                           inet->saddr, inet->daddr, NULL);
-               if (err == NET_XMIT_CN)
-                       err = 0;
-       }
-
-       return err;
-}
-
 static inline u64 dccp_v4_init_sequence(const struct sock *sk,
                                        const struct sk_buff *skb)
 {
@@ -497,9 +459,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        struct dccp_sock dp;
        struct request_sock *req;
        struct dccp_request_sock *dreq;
-       const __u32 saddr = skb->nh.iph->saddr;
-       const __u32 daddr = skb->nh.iph->daddr;
-       const __u32 service = dccp_hdr_request(skb)->dccph_req_service;
+       const __be32 saddr = skb->nh.iph->saddr;
+       const __be32 daddr = skb->nh.iph->daddr;
+       const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
        struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
        __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
 
@@ -535,7 +497,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        if (req == NULL)
                goto drop;
 
-       /* FIXME: process options */
+       if (dccp_parse_options(sk, skb))
+               goto drop;
 
        dccp_openreq_init(req, &dp, skb);
 
@@ -660,8 +623,8 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
        return sk;
 }
 
-int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr,
-                    const u32 daddr)
+int dccp_v4_checksum(const struct sk_buff *skb, const __be32 saddr,
+                    const __be32 daddr)
 {
        const struct dccp_hdr* dh = dccp_hdr(skb);
        int checksum_len;
@@ -680,8 +643,10 @@ int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr,
                                 IPPROTO_DCCP, tmp);
 }
 
+EXPORT_SYMBOL_GPL(dccp_v4_checksum);
+
 static int dccp_v4_verify_checksum(struct sk_buff *skb,
-                                  const u32 saddr, const u32 daddr)
+                                  const __be32 saddr, const __be32 daddr)
 {
        struct dccp_hdr *dh = dccp_hdr(skb);
        int checksum_len;
@@ -741,16 +706,17 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
        if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
                return;
 
-       dst = dccp_v4_route_skb(dccp_ctl_socket->sk, rxskb);
+       dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb);
        if (dst == NULL)
                return;
 
-       skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC);
+       skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header,
+                       GFP_ATOMIC);
        if (skb == NULL)
                goto out;
 
        /* Reserve space for headers. */
-       skb_reserve(skb, MAX_DCCP_HEADER);
+       skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header);
        skb->dst = dst_clone(dst);
 
        skb->h.raw = skb_push(skb, dccp_hdr_reset_len);
@@ -778,11 +744,11 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
        dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr,
                                              rxskb->nh.iph->daddr);
 
-       bh_lock_sock(dccp_ctl_socket->sk);
-       err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
+       bh_lock_sock(dccp_v4_ctl_socket->sk);
+       err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk,
                                    rxskb->nh.iph->daddr,
                                    rxskb->nh.iph->saddr, NULL);
-       bh_unlock_sock(dccp_ctl_socket->sk);
+       bh_unlock_sock(dccp_v4_ctl_socket->sk);
 
        if (err == NET_XMIT_CN || err == 0) {
                DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
@@ -912,7 +878,7 @@ int dccp_invalid_packet(struct sk_buff *skb)
 EXPORT_SYMBOL_GPL(dccp_invalid_packet);
 
 /* this is called when real data arrives */
-int dccp_v4_rcv(struct sk_buff *skb)
+static int dccp_v4_rcv(struct sk_buff *skb)
 {
        const struct dccp_hdr *dh;
        struct sock *sk;
@@ -1019,111 +985,37 @@ do_time_wait:
        goto no_dccp_socket;
 }
 
-struct inet_connection_sock_af_ops dccp_ipv4_af_ops = {
-       .queue_xmit     = ip_queue_xmit,
-       .send_check     = dccp_v4_send_check,
-       .rebuild_header = inet_sk_rebuild_header,
-       .conn_request   = dccp_v4_conn_request,
-       .syn_recv_sock  = dccp_v4_request_recv_sock,
-       .net_header_len = sizeof(struct iphdr),
-       .setsockopt     = ip_setsockopt,
-       .getsockopt     = ip_getsockopt,
-       .addr2sockaddr  = inet_csk_addr2sockaddr,
-       .sockaddr_len   = sizeof(struct sockaddr_in),
+static struct inet_connection_sock_af_ops dccp_ipv4_af_ops = {
+       .queue_xmit        = ip_queue_xmit,
+       .send_check        = dccp_v4_send_check,
+       .rebuild_header    = inet_sk_rebuild_header,
+       .conn_request      = dccp_v4_conn_request,
+       .syn_recv_sock     = dccp_v4_request_recv_sock,
+       .net_header_len    = sizeof(struct iphdr),
+       .setsockopt        = ip_setsockopt,
+       .getsockopt        = ip_getsockopt,
+       .addr2sockaddr     = inet_csk_addr2sockaddr,
+       .sockaddr_len      = sizeof(struct sockaddr_in),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ip_setsockopt,
+       .compat_getsockopt = compat_ip_getsockopt,
+#endif
 };
 
-int dccp_v4_init_sock(struct sock *sk)
-{
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct inet_connection_sock *icsk = inet_csk(sk);
-       static int dccp_ctl_socket_init = 1;
-
-       dccp_options_init(&dp->dccps_options);
-       do_gettimeofday(&dp->dccps_epoch);
-
-       if (dp->dccps_options.dccpo_send_ack_vector) {
-               dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN,
-                                                          GFP_KERNEL);
-               if (dp->dccps_hc_rx_ackvec == NULL)
-                       return -ENOMEM;
-       }
-
-       /*
-        * FIXME: We're hardcoding the CCID, and doing this at this point makes
-        * the listening (master) sock get CCID control blocks, which is not
-        * necessary, but for now, to not mess with the test userspace apps,
-        * lets leave it here, later the real solution is to do this in a
-        * setsockopt(CCIDs-I-want/accept). -acme
-        */
-       if (likely(!dccp_ctl_socket_init)) {
-               dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_rx_ccid,
-                                                sk);
-               dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_tx_ccid,
-                                                sk);
-               if (dp->dccps_hc_rx_ccid == NULL ||
-                   dp->dccps_hc_tx_ccid == NULL) {
-                       ccid_exit(dp->dccps_hc_rx_ccid, sk);
-                       ccid_exit(dp->dccps_hc_tx_ccid, sk);
-                       if (dp->dccps_options.dccpo_send_ack_vector) {
-                               dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
-                               dp->dccps_hc_rx_ackvec = NULL;
-                       }
-                       dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
-                       return -ENOMEM;
-               }
-       } else
-               dccp_ctl_socket_init = 0;
-
-       dccp_init_xmit_timers(sk);
-       icsk->icsk_rto = DCCP_TIMEOUT_INIT;
-       sk->sk_state = DCCP_CLOSED;
-       sk->sk_write_space = dccp_write_space;
-       icsk->icsk_af_ops = &dccp_ipv4_af_ops;
-       icsk->icsk_sync_mss = dccp_sync_mss;
-       dp->dccps_mss_cache = 536;
-       dp->dccps_role = DCCP_ROLE_UNDEFINED;
-       dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
-
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(dccp_v4_init_sock);
-
-int dccp_v4_destroy_sock(struct sock *sk)
+static int dccp_v4_init_sock(struct sock *sk)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
+       static __u8 dccp_v4_ctl_sock_initialized;
+       int err = dccp_init_sock(sk, dccp_v4_ctl_sock_initialized);
 
-       /*
-        * DCCP doesn't use sk_write_queue, just sk_send_head
-        * for retransmissions
-        */
-       if (sk->sk_send_head != NULL) {
-               kfree_skb(sk->sk_send_head);
-               sk->sk_send_head = NULL;
+       if (err == 0) {
+               if (unlikely(!dccp_v4_ctl_sock_initialized))
+                       dccp_v4_ctl_sock_initialized = 1;
+               inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops;
        }
 
-       /* Clean up a referenced DCCP bind bucket. */
-       if (inet_csk(sk)->icsk_bind_hash != NULL)
-               inet_put_port(&dccp_hashinfo, sk);
-
-       kfree(dp->dccps_service_list);
-       dp->dccps_service_list = NULL;
-
-       ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
-       ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
-       if (dp->dccps_options.dccpo_send_ack_vector) {
-               dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
-               dp->dccps_hc_rx_ackvec = NULL;
-       }
-       ccid_exit(dp->dccps_hc_rx_ccid, sk);
-       ccid_exit(dp->dccps_hc_tx_ccid, sk);
-       dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
-
-       return 0;
+       return err;
 }
 
-EXPORT_SYMBOL_GPL(dccp_v4_destroy_sock);
-
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
        kfree(inet_rsk(req)->opt);
@@ -1142,7 +1034,7 @@ static struct timewait_sock_ops dccp_timewait_sock_ops = {
        .twsk_obj_size  = sizeof(struct inet_timewait_sock),
 };
 
-struct proto dccp_prot = {
+static struct proto dccp_v4_prot = {
        .name                   = "DCCP",
        .owner                  = THIS_MODULE,
        .close                  = dccp_close,
@@ -1155,17 +1047,110 @@ struct proto dccp_prot = {
        .sendmsg                = dccp_sendmsg,
        .recvmsg                = dccp_recvmsg,
        .backlog_rcv            = dccp_v4_do_rcv,
-       .hash                   = dccp_v4_hash,
+       .hash                   = dccp_hash,
        .unhash                 = dccp_unhash,
        .accept                 = inet_csk_accept,
        .get_port               = dccp_v4_get_port,
        .shutdown               = dccp_shutdown,
-       .destroy                = dccp_v4_destroy_sock,
+       .destroy                = dccp_destroy_sock,
        .orphan_count           = &dccp_orphan_count,
        .max_header             = MAX_DCCP_HEADER,
        .obj_size               = sizeof(struct dccp_sock),
        .rsk_prot               = &dccp_request_sock_ops,
        .twsk_prot              = &dccp_timewait_sock_ops,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt      = compat_dccp_setsockopt,
+       .compat_getsockopt      = compat_dccp_getsockopt,
+#endif
+};
+
+static struct net_protocol dccp_v4_protocol = {
+       .handler        = dccp_v4_rcv,
+       .err_handler    = dccp_v4_err,
+       .no_policy      = 1,
+};
+
+static const struct proto_ops inet_dccp_ops = {
+       .family            = PF_INET,
+       .owner             = THIS_MODULE,
+       .release           = inet_release,
+       .bind              = inet_bind,
+       .connect           = inet_stream_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = inet_accept,
+       .getname           = inet_getname,
+       /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
+       .poll              = dccp_poll,
+       .ioctl             = inet_ioctl,
+       /* FIXME: work on inet_listen to rename it to sock_common_listen */
+       .listen            = inet_dccp_listen,
+       .shutdown          = inet_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
-EXPORT_SYMBOL_GPL(dccp_prot);
+static struct inet_protosw dccp_v4_protosw = {
+       .type           = SOCK_DCCP,
+       .protocol       = IPPROTO_DCCP,
+       .prot           = &dccp_v4_prot,
+       .ops            = &inet_dccp_ops,
+       .capability     = -1,
+       .no_check       = 0,
+       .flags          = INET_PROTOSW_ICSK,
+};
+
+static int __init dccp_v4_init(void)
+{
+       int err = proto_register(&dccp_v4_prot, 1);
+
+       if (err != 0)
+               goto out;
+
+       err = inet_add_protocol(&dccp_v4_protocol, IPPROTO_DCCP);
+       if (err != 0)
+               goto out_proto_unregister;
+
+       inet_register_protosw(&dccp_v4_protosw);
+
+       err = inet_csk_ctl_sock_create(&dccp_v4_ctl_socket, PF_INET,
+                                      SOCK_DCCP, IPPROTO_DCCP);
+       if (err)
+               goto out_unregister_protosw;
+out:
+       return err;
+out_unregister_protosw:
+       inet_unregister_protosw(&dccp_v4_protosw);
+       inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP);
+out_proto_unregister:
+       proto_unregister(&dccp_v4_prot);
+       goto out;
+}
+
+static void __exit dccp_v4_exit(void)
+{
+       inet_unregister_protosw(&dccp_v4_protosw);
+       inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP);
+       proto_unregister(&dccp_v4_prot);
+}
+
+module_init(dccp_v4_init);
+module_exit(dccp_v4_exit);
+
+/*
+ * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
+ * values directly, Also cover the case where the protocol is not specified,
+ * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
+ */
+MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
+MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
+MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");
index 80c4d04..65e2ab0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *     DCCP over IPv6
- *     Linux INET6 implementation 
+ *     Linux INET6 implementation
  *
  *     Based on net/dccp6/ipv6.c
  *
@@ -33,6 +33,9 @@
 #include "dccp.h"
 #include "ipv6.h"
 
+/* Socket used for sending RSTs and ACKs */
+static struct socket *dccp_v6_ctl_socket;
+
 static void dccp_v6_ctl_send_reset(struct sk_buff *skb);
 static void dccp_v6_reqsk_send_ack(struct sk_buff *skb,
                                   struct request_sock *req);
@@ -53,7 +56,7 @@ static void dccp_v6_hash(struct sock *sk)
 {
        if (sk->sk_state != DCCP_CLOSED) {
                if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) {
-                       dccp_prot.hash(sk);
+                       dccp_hash(sk);
                        return;
                }
                local_bh_disable();
@@ -63,8 +66,8 @@ static void dccp_v6_hash(struct sock *sk)
 }
 
 static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len,
-                               struct in6_addr *saddr, 
-                               struct in6_addr *daddr, 
+                               struct in6_addr *saddr,
+                               struct in6_addr *daddr,
                                unsigned long base)
 {
        return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base);
@@ -79,17 +82,17 @@ static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
                                                    skb->nh.ipv6h->saddr.s6_addr32,
                                                    dh->dccph_dport,
                                                    dh->dccph_sport);
-       else
-               return secure_dccp_sequence_number(skb->nh.iph->daddr,
-                                                  skb->nh.iph->saddr,
-                                                  dh->dccph_dport,
-                                                  dh->dccph_sport);
+
+       return secure_dccp_sequence_number(skb->nh.iph->daddr,
+                                          skb->nh.iph->saddr,
+                                          dh->dccph_dport,
+                                          dh->dccph_sport);
 }
 
-static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 
+static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                           int addr_len)
 {
-       struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
+       struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr;
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct inet_sock *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -102,10 +105,10 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        dp->dccps_role = DCCP_ROLE_CLIENT;
 
-       if (addr_len < SIN6_LEN_RFC2133) 
+       if (addr_len < SIN6_LEN_RFC2133)
                return -EINVAL;
 
-       if (usin->sin6_family != AF_INET6) 
+       if (usin->sin6_family != AF_INET6)
                return -EAFNOSUPPORT;
 
        memset(&fl, 0, sizeof(fl));
@@ -122,17 +125,15 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                        fl6_sock_release(flowlabel);
                }
        }
-
        /*
-        *      connect() to INADDR_ANY means loopback (BSD'ism).
-        */
-       
-       if (ipv6_addr_any(&usin->sin6_addr))
-               usin->sin6_addr.s6_addr[15] = 0x1; 
+        * connect() to INADDR_ANY means loopback (BSD'ism).
+        */
+       if (ipv6_addr_any(&usin->sin6_addr))
+               usin->sin6_addr.s6_addr[15] = 1;
 
        addr_type = ipv6_addr_type(&usin->sin6_addr);
 
-       if(addr_type & IPV6_ADDR_MULTICAST)
+       if (addr_type & IPV6_ADDR_MULTICAST)
                return -ENETUNREACH;
 
        if (addr_type & IPV6_ADDR_LINKLOCAL) {
@@ -157,9 +158,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        np->flow_label = fl.fl6_flowlabel;
 
        /*
-        *      DCCP over IPv4
+        * DCCP over IPv4
         */
-
        if (addr_type == IPV6_ADDR_MAPPED) {
                u32 exthdrlen = icsk->icsk_ext_hdr_len;
                struct sockaddr_in sin;
@@ -177,7 +177,6 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                sk->sk_backlog_rcv = dccp_v4_do_rcv;
 
                err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
-
                if (err) {
                        icsk->icsk_ext_hdr_len = exthdrlen;
                        icsk->icsk_af_ops = &dccp_ipv6_af_ops;
@@ -203,8 +202,9 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        fl.fl_ip_dport = usin->sin6_port;
        fl.fl_ip_sport = inet->sport;
 
-       if (np->opt && np->opt->srcrt) {
-               struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
+       if (np->opt != NULL && np->opt->srcrt != NULL) {
+               const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
+
                ipv6_addr_copy(&final, &fl.fl6_dst);
                ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
                final_p = &final;
@@ -213,10 +213,12 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        err = ip6_dst_lookup(sk, &dst, &fl);
        if (err)
                goto failure;
+
        if (final_p)
                ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-       if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+       err = xfrm_lookup(&dst, &fl, sk, 0);
+       if (err < 0)
                goto failure;
 
        if (saddr == NULL) {
@@ -231,7 +233,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        ip6_dst_store(sk, dst, NULL);
 
        icsk->icsk_ext_hdr_len = 0;
-       if (np->opt)
+       if (np->opt != NULL)
                icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
                                          np->opt->opt_nflen);
 
@@ -264,7 +266,7 @@ failure:
 }
 
 static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                       int type, int code, int offset, __u32 info)
+                       int type, int code, int offset, __be32 info)
 {
        struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;
        const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
@@ -305,7 +307,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
                /* icmp should have updated the destination cache entry */
                dst = __sk_dst_check(sk, np->dst_cookie);
-
                if (dst == NULL) {
                        struct inet_sock *inet = inet_sk(sk);
                        struct flowi fl;
@@ -322,16 +323,17 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                        fl.fl_ip_dport = inet->dport;
                        fl.fl_ip_sport = inet->sport;
 
-                       if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
+                       err = ip6_dst_lookup(sk, &dst, &fl);
+                       if (err) {
                                sk->sk_err_soft = -err;
                                goto out;
                        }
 
-                       if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+                       err = xfrm_lookup(&dst, &fl, sk, 0);
+                       if (err < 0) {
                                sk->sk_err_soft = -err;
                                goto out;
                        }
-
                } else
                        dst_hold(dst);
 
@@ -355,11 +357,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,
                                           &hdr->daddr, &hdr->saddr,
                                           inet6_iif(skb));
-               if (!req)
+               if (req == NULL)
                        goto out;
 
-               /* ICMPs are not backlogged, hence we cannot get
-                * an established socket here.
+               /*
+                * ICMPs are not backlogged, hence we cannot get an established
+                * socket here.
                 */
                BUG_TRAP(req->sk == NULL);
 
@@ -373,7 +376,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        case DCCP_REQUESTING:
        case DCCP_RESPOND:  /* Cannot happen.
-                              It can, it SYNs are crossed. --ANK */ 
+                              It can, it SYNs are crossed. --ANK */
                if (!sock_owned_by_user(sk)) {
                        DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
                        sk->sk_err = err;
@@ -382,7 +385,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                         * (see connect in sock.c)
                         */
                        sk->sk_error_report(sk);
-
                        dccp_done(sk);
                } else
                        sk->sk_err_soft = err;
@@ -428,14 +430,16 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
                    ireq6->pktopts) {
                        struct sk_buff *pktopts = ireq6->pktopts;
                        struct inet6_skb_parm *rxopt = IP6CB(pktopts);
+
                        if (rxopt->srcrt)
                                opt = ipv6_invert_rthdr(sk,
                                        (struct ipv6_rt_hdr *)(pktopts->nh.raw +
                                                               rxopt->srcrt));
                }
 
-               if (opt && opt->srcrt) {
-                       struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
+               if (opt != NULL && opt->srcrt != NULL) {
+                       const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
+
                        ipv6_addr_copy(&final, &fl.fl6_dst);
                        ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
                        final_p = &final;
@@ -444,15 +448,19 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
                err = ip6_dst_lookup(sk, &dst, &fl);
                if (err)
                        goto done;
+
                if (final_p)
                        ipv6_addr_copy(&fl.fl6_dst, final_p);
-               if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+
+               err = xfrm_lookup(&dst, &fl, sk, 0);
+               if (err < 0)
                        goto done;
        }
 
        skb = dccp_make_response(sk, dst, req);
        if (skb != NULL) {
                struct dccp_hdr *dh = dccp_hdr(skb);
+
                dh->dccph_checksum = dccp_v6_check(dh, skb->len,
                                                   &ireq6->loc_addr,
                                                   &ireq6->rmt_addr,
@@ -466,7 +474,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
        }
 
 done:
-        if (opt && opt != np->opt)
+       if (opt != NULL && opt != np->opt)
                sock_kfree_s(sk, opt, opt->tot_len);
        dst_release(dst);
        return err;
@@ -497,7 +505,7 @@ static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
        struct dccp_hdr *dh = dccp_hdr(skb);
 
        dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr,
-                                            len, IPPROTO_DCCP, 
+                                            len, IPPROTO_DCCP,
                                             csum_partial((char *)dh,
                                                          dh->dccph_doff << 2,
                                                          skb->csum));
@@ -505,8 +513,8 @@ static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
 
 static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
 {
-       struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; 
-       const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
+       struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
+       const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
                                       sizeof(struct dccp_hdr_ext) +
                                       sizeof(struct dccp_hdr_reset);
        struct sk_buff *skb;
@@ -517,20 +525,14 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
                return;
 
        if (!ipv6_unicast_destination(rxskb))
-               return; 
-
-       /*
-        * We need to grab some memory, and put together an RST,
-        * and then put it into the queue to be sent.
-        */
+               return;
 
-       skb = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) +
-                       dccp_hdr_reset_len, GFP_ATOMIC);
-       if (skb == NULL) 
+       skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header,
+                       GFP_ATOMIC);
+       if (skb == NULL)
                return;
 
-       skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr) +
-                   dccp_hdr_reset_len);
+       skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header);
 
        skb->h.raw = skb_push(skb, dccp_hdr_reset_len);
        dh = dccp_hdr(skb);
@@ -568,7 +570,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
        /* sk = NULL, but it is safe for now. RST socket required. */
        if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
                if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
-                       ip6_xmit(NULL, skb, &fl, NULL, 0);
+                       ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
                        return;
@@ -578,22 +580,22 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
        kfree_skb(skb);
 }
 
-static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb)
+static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb,
+                                  struct request_sock *req)
 {
        struct flowi fl;
        struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
-       const int dccp_hdr_ack_len = sizeof(struct dccp_hdr) +
+       const u32 dccp_hdr_ack_len = sizeof(struct dccp_hdr) +
                                     sizeof(struct dccp_hdr_ext) +
                                     sizeof(struct dccp_hdr_ack_bits);
        struct sk_buff *skb;
 
-       skb = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) +
-                       dccp_hdr_ack_len, GFP_ATOMIC);
+       skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header,
+                       GFP_ATOMIC);
        if (skb == NULL)
                return;
 
-       skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr) +
-                        dccp_hdr_ack_len);
+       skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header);
 
        skb->h.raw = skb_push(skb, dccp_hdr_ack_len);
        dh = dccp_hdr(skb);
@@ -605,7 +607,7 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb)
        dh->dccph_dport = rxdh->dccph_sport;
        dh->dccph_doff  = dccp_hdr_ack_len / 4;
        dh->dccph_x     = 1;
-       
+
        dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq);
        dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
                         DCCP_SKB_CB(rxskb)->dccpd_seq);
@@ -623,7 +625,7 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb)
 
        if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
                if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
-                       ip6_xmit(NULL, skb, &fl, NULL, 0);
+                       ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
                        return;
                }
@@ -632,12 +634,6 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb)
        kfree_skb(skb);
 }
 
-static void dccp_v6_reqsk_send_ack(struct sk_buff *skb,
-                                  struct request_sock *req)
-{
-       dccp_v6_ctl_send_ack(skb);
-}
-
 static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 {
        const struct dccp_hdr *dh = dccp_hdr(skb);
@@ -657,7 +653,6 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
                                         &iph->saddr, dh->dccph_sport,
                                         &iph->daddr, ntohs(dh->dccph_dport),
                                         inet6_iif(skb));
-
        if (nsk != NULL) {
                if (nsk->sk_state != DCCP_TIME_WAIT) {
                        bh_lock_sock(nsk);
@@ -678,7 +673,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        struct dccp_request_sock *dreq;
        struct inet6_request_sock *ireq6;
        struct ipv6_pinfo *np = inet6_sk(sk);
-       const __u32 service = dccp_hdr_request(skb)->dccph_req_service;
+       const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
        struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
        __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
 
@@ -686,17 +681,17 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                return dccp_v4_conn_request(sk, skb);
 
        if (!ipv6_unicast_destination(skb))
-               goto drop; 
+               goto drop;
 
        if (dccp_bad_service_code(sk, service)) {
                reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
                goto drop;
        }
        /*
-        *      There are no SYN attacks on IPv6, yet...        
+        * There are no SYN attacks on IPv6, yet...
         */
        if (inet_csk_reqsk_queue_is_full(sk))
-               goto drop;              
+               goto drop;
 
        if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
                goto drop;
@@ -730,7 +725,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
            ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
                ireq6->iif = inet6_iif(skb);
 
-       /* 
+       /*
         * Step 3: Process LISTEN state
         *
         * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
@@ -774,9 +769,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
                /*
                 *      v6 mapped
                 */
-
                newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);
-               if (newsk == NULL) 
+               if (newsk == NULL)
                        return NULL;
 
                newdp6 = (struct dccp6_sock *)newsk;
@@ -822,9 +816,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
        if (sk_acceptq_is_full(sk))
                goto out_overflow;
 
-       if (np->rxopt.bits.osrcrt == 2 &&
-           opt == NULL && ireq6->pktopts) {
-               struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts);
+       if (np->rxopt.bits.osrcrt == 2 && opt == NULL && ireq6->pktopts) {
+               const struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts);
+
                if (rxopt->srcrt)
                        opt = ipv6_invert_rthdr(sk,
                                (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw +
@@ -838,8 +832,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
                memset(&fl, 0, sizeof(fl));
                fl.proto = IPPROTO_DCCP;
                ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
-               if (opt && opt->srcrt) {
-                       struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+               if (opt != NULL && opt->srcrt != NULL) {
+                       const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
+
                        ipv6_addr_copy(&final, &fl.fl6_dst);
                        ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
                        final_p = &final;
@@ -857,7 +852,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 
                if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
                        goto out;
-       } 
+       }
 
        newsk = dccp_create_openreq_child(sk, req, skb);
        if (newsk == NULL)
@@ -870,9 +865,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
         */
 
        ip6_dst_store(newsk, dst, NULL);
-       newsk->sk_route_caps = dst->dev->features &
-               ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
-
+       newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
+                                                     NETIF_F_TSO);
        newdp6 = (struct dccp6_sock *)newsk;
        newinet = inet_sk(newsk);
        newinet->pinet6 = &newdp6->inet6;
@@ -886,7 +880,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
        ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr);
        newsk->sk_bound_dev_if = ireq6->iif;
 
-       /* Now IPv6 options... 
+       /* Now IPv6 options...
 
           First: no IPv4 options.
         */
@@ -908,20 +902,20 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
        newnp->mcast_oif  = inet6_iif(skb);
        newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
 
-       /* Clone native IPv6 options from listening socket (if any)
-
-          Yes, keeping reference count would be much more clever,
-          but we make one more one thing there: reattach optmem
-          to newsk.
+       /*
+        * Clone native IPv6 options from listening socket (if any)
+        *
+        * Yes, keeping reference count would be much more clever, but we make
+        * one more one thing there: reattach optmem to newsk.
         */
-       if (opt) {
+       if (opt != NULL) {
                newnp->opt = ipv6_dup_options(newsk, opt);
                if (opt != np->opt)
                        sock_kfree_s(sk, opt, opt->tot_len);
        }
 
        inet_csk(newsk)->icsk_ext_hdr_len = 0;
-       if (newnp->opt)
+       if (newnp->opt != NULL)
                inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
                                                     newnp->opt->opt_flen);
 
@@ -938,7 +932,7 @@ out_overflow:
        NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
 out:
        NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
-       if (opt && opt != np->opt)
+       if (opt != NULL && opt != np->opt)
                sock_kfree_s(sk, opt, opt->tot_len);
        dst_release(dst);
        return NULL;
@@ -972,8 +966,8 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                goto discard;
 
        /*
-        *      socket locking is here for SMP purposes as backlog rcv
-        *      is currently called with bh processing disabled.
+        * socket locking is here for SMP purposes as backlog rcv is currently
+        * called with bh processing disabled.
         */
 
        /* Do Stevens' IPV6_PKTOPTIONS.
@@ -998,20 +992,20 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                return 0;
        }
 
-       if (sk->sk_state == DCCP_LISTEN) { 
+       if (sk->sk_state == DCCP_LISTEN) {
                struct sock *nsk = dccp_v6_hnd_req(sk, skb);
-               if (!nsk)
-                       goto discard;
 
+               if (nsk == NULL)
+                       goto discard;
                /*
                 * Queue it on the new socket if the new socket is active,
                 * otherwise we just shortcircuit this and continue with
                 * the new socket..
                 */
-               if(nsk != sk) {
+               if (nsk != sk) {
                        if (dccp_child_process(sk, nsk, skb))
                                goto reset;
-                       if (opt_skb)
+                       if (opt_skb != NULL)
                                __kfree_skb(opt_skb);
                        return 0;
                }
@@ -1024,7 +1018,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 reset:
        dccp_v6_ctl_send_reset(skb);
 discard:
-       if (opt_skb)
+       if (opt_skb != NULL)
                __kfree_skb(opt_skb);
        kfree_skb(skb);
        return 0;
@@ -1057,7 +1051,7 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
                            dh->dccph_sport,
                            &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
                            inet6_iif(skb));
-       /* 
+       /*
         * Step 2:
         *      If no socket ...
         *              Generate Reset(No Connection) unless P.type == Reset
@@ -1066,15 +1060,14 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
        if (sk == NULL)
                goto no_dccp_socket;
 
-       /* 
+       /*
         * Step 2:
         *      ... or S.state == TIMEWAIT,
         *              Generate Reset(No Connection) unless P.type == Reset
         *              Drop packet and return
         */
-              
        if (sk->sk_state == DCCP_TIME_WAIT)
-                goto do_time_wait;
+               goto do_time_wait;
 
        if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_and_relse;
@@ -1113,32 +1106,40 @@ do_time_wait:
 }
 
 static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
-       .queue_xmit     =       inet6_csk_xmit,
-       .send_check     =       dccp_v6_send_check,
-       .rebuild_header =       inet6_sk_rebuild_header,
-       .conn_request   =       dccp_v6_conn_request,
-       .syn_recv_sock  =       dccp_v6_request_recv_sock,
-       .net_header_len =       sizeof(struct ipv6hdr),
-       .setsockopt     =       ipv6_setsockopt,
-       .getsockopt     =       ipv6_getsockopt,
-       .addr2sockaddr  =       inet6_csk_addr2sockaddr,
-       .sockaddr_len   =       sizeof(struct sockaddr_in6)
+       .queue_xmit        = inet6_csk_xmit,
+       .send_check        = dccp_v6_send_check,
+       .rebuild_header    = inet6_sk_rebuild_header,
+       .conn_request      = dccp_v6_conn_request,
+       .syn_recv_sock     = dccp_v6_request_recv_sock,
+       .net_header_len    = sizeof(struct ipv6hdr),
+       .setsockopt        = ipv6_setsockopt,
+       .getsockopt        = ipv6_getsockopt,
+       .addr2sockaddr     = inet6_csk_addr2sockaddr,
+       .sockaddr_len      = sizeof(struct sockaddr_in6),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ipv6_setsockopt,
+       .compat_getsockopt = compat_ipv6_getsockopt,
+#endif
 };
 
 /*
  *     DCCP over IPv4 via INET6 API
  */
 static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
-       .queue_xmit     =       ip_queue_xmit,
-       .send_check     =       dccp_v4_send_check,
-       .rebuild_header =       inet_sk_rebuild_header,
-       .conn_request   =       dccp_v6_conn_request,
-       .syn_recv_sock  =       dccp_v6_request_recv_sock,
-       .net_header_len =       sizeof(struct iphdr),
-       .setsockopt     =       ipv6_setsockopt,
-       .getsockopt     =       ipv6_getsockopt,
-       .addr2sockaddr  =       inet6_csk_addr2sockaddr,
-       .sockaddr_len   =       sizeof(struct sockaddr_in6)
+       .queue_xmit        = ip_queue_xmit,
+       .send_check        = dccp_v4_send_check,
+       .rebuild_header    = inet_sk_rebuild_header,
+       .conn_request      = dccp_v6_conn_request,
+       .syn_recv_sock     = dccp_v6_request_recv_sock,
+       .net_header_len    = sizeof(struct iphdr),
+       .setsockopt        = ipv6_setsockopt,
+       .getsockopt        = ipv6_getsockopt,
+       .addr2sockaddr     = inet6_csk_addr2sockaddr,
+       .sockaddr_len      = sizeof(struct sockaddr_in6),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ipv6_setsockopt,
+       .compat_getsockopt = compat_ipv6_getsockopt,
+#endif
 };
 
 /* NOTE: A lot of things set to zero explicitly by call to
@@ -1146,71 +1147,83 @@ static struct inet_connection_sock_af_ops dccp_ipv6_mapped = {
  */
 static int dccp_v6_init_sock(struct sock *sk)
 {
-       int err = dccp_v4_init_sock(sk);
+       static __u8 dccp_v6_ctl_sock_initialized;
+       int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized);
 
-       if (err == 0)
+       if (err == 0) {
+               if (unlikely(!dccp_v6_ctl_sock_initialized))
+                       dccp_v6_ctl_sock_initialized = 1;
                inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops;
+       }
 
        return err;
 }
 
 static int dccp_v6_destroy_sock(struct sock *sk)
 {
-       dccp_v4_destroy_sock(sk);
+       dccp_destroy_sock(sk);
        return inet6_destroy_sock(sk);
 }
 
 static struct proto dccp_v6_prot = {
-       .name                   = "DCCPv6",
-       .owner                  = THIS_MODULE,
-       .close                  = dccp_close,
-       .connect                = dccp_v6_connect,
-       .disconnect             = dccp_disconnect,
-       .ioctl                  = dccp_ioctl,
-       .init                   = dccp_v6_init_sock,
-       .setsockopt             = dccp_setsockopt,
-       .getsockopt             = dccp_getsockopt,
-       .sendmsg                = dccp_sendmsg,
-       .recvmsg                = dccp_recvmsg,
-       .backlog_rcv            = dccp_v6_do_rcv,
-       .hash                   = dccp_v6_hash,
-       .unhash                 = dccp_unhash,
-       .accept                 = inet_csk_accept,
-       .get_port               = dccp_v6_get_port,
-       .shutdown               = dccp_shutdown,
-       .destroy                = dccp_v6_destroy_sock,
-       .orphan_count           = &dccp_orphan_count,
-       .max_header             = MAX_DCCP_HEADER,
-       .obj_size               = sizeof(struct dccp6_sock),
-       .rsk_prot               = &dccp6_request_sock_ops,
-       .twsk_prot              = &dccp6_timewait_sock_ops,
+       .name              = "DCCPv6",
+       .owner             = THIS_MODULE,
+       .close             = dccp_close,
+       .connect           = dccp_v6_connect,
+       .disconnect        = dccp_disconnect,
+       .ioctl             = dccp_ioctl,
+       .init              = dccp_v6_init_sock,
+       .setsockopt        = dccp_setsockopt,
+       .getsockopt        = dccp_getsockopt,
+       .sendmsg           = dccp_sendmsg,
+       .recvmsg           = dccp_recvmsg,
+       .backlog_rcv       = dccp_v6_do_rcv,
+       .hash              = dccp_v6_hash,
+       .unhash            = dccp_unhash,
+       .accept            = inet_csk_accept,
+       .get_port          = dccp_v6_get_port,
+       .shutdown          = dccp_shutdown,
+       .destroy           = dccp_v6_destroy_sock,
+       .orphan_count      = &dccp_orphan_count,
+       .max_header        = MAX_DCCP_HEADER,
+       .obj_size          = sizeof(struct dccp6_sock),
+       .rsk_prot          = &dccp6_request_sock_ops,
+       .twsk_prot         = &dccp6_timewait_sock_ops,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_dccp_setsockopt,
+       .compat_getsockopt = compat_dccp_getsockopt,
+#endif
 };
 
 static struct inet6_protocol dccp_v6_protocol = {
-       .handler        =       dccp_v6_rcv,
-       .err_handler    =       dccp_v6_err,
-       .flags          =       INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
+       .handler        = dccp_v6_rcv,
+       .err_handler    = dccp_v6_err,
+       .flags          = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
 };
 
 static struct proto_ops inet6_dccp_ops = {
-       .family         = PF_INET6,
-       .owner          = THIS_MODULE,
-       .release        = inet6_release,
-       .bind           = inet6_bind,
-       .connect        = inet_stream_connect,
-       .socketpair     = sock_no_socketpair,
-       .accept         = inet_accept,
-       .getname        = inet6_getname,
-       .poll           = dccp_poll,
-       .ioctl          = inet6_ioctl,
-       .listen         = inet_dccp_listen,
-       .shutdown       = inet_shutdown,
-       .setsockopt     = sock_common_setsockopt,
-       .getsockopt     = sock_common_getsockopt,
-       .sendmsg        = inet_sendmsg,
-       .recvmsg        = sock_common_recvmsg,
-       .mmap           = sock_no_mmap,
-       .sendpage       = sock_no_sendpage,
+       .family            = PF_INET6,
+       .owner             = THIS_MODULE,
+       .release           = inet6_release,
+       .bind              = inet6_bind,
+       .connect           = inet_stream_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = inet_accept,
+       .getname           = inet6_getname,
+       .poll              = dccp_poll,
+       .ioctl             = inet6_ioctl,
+       .listen            = inet_dccp_listen,
+       .shutdown          = inet_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 static struct inet_protosw dccp_v6_protosw = {
@@ -1234,8 +1247,16 @@ static int __init dccp_v6_init(void)
                goto out_unregister_proto;
 
        inet6_register_protosw(&dccp_v6_protosw);
+
+       err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6,
+                                      SOCK_DCCP, IPPROTO_DCCP);
+       if (err != 0)
+               goto out_unregister_protosw;
 out:
        return err;
+out_unregister_protosw:
+       inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP);
+       inet6_unregister_protosw(&dccp_v6_protosw);
 out_unregister_proto:
        proto_unregister(&dccp_v6_prot);
        goto out;
index 29261fc..c0349e5 100644 (file)
@@ -22,6 +22,7 @@
 #include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
 struct inet_timewait_death_row dccp_death_row = {
        .sysctl_max_tw_buckets = NR_FILE * 2,
@@ -106,6 +107,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
                const struct dccp_request_sock *dreq = dccp_rsk(req);
                struct inet_connection_sock *newicsk = inet_csk(sk);
                struct dccp_sock *newdp = dccp_sk(newsk);
+               struct dccp_minisock *newdmsk = dccp_msk(newsk);
 
                newdp->dccps_role          = DCCP_ROLE_SERVER;
                newdp->dccps_hc_rx_ackvec  = NULL;
@@ -114,27 +116,27 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
                newicsk->icsk_rto          = DCCP_TIMEOUT_INIT;
                do_gettimeofday(&newdp->dccps_epoch);
 
-               if (newdp->dccps_options.dccpo_send_ack_vector) {
+               if (dccp_feat_clone(sk, newsk))
+                       goto out_free;
+
+               if (newdmsk->dccpms_send_ack_vector) {
                        newdp->dccps_hc_rx_ackvec =
-                               dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN,
-                                                 GFP_ATOMIC);
-                       /*
-                        * XXX: We're using the same CCIDs set on the parent,
-                        * i.e. sk_clone copied the master sock and left the
-                        * CCID pointers for this child, that is why we do the
-                        * __ccid_get calls.
-                        */
+                                               dccp_ackvec_alloc(GFP_ATOMIC);
                        if (unlikely(newdp->dccps_hc_rx_ackvec == NULL))
                                goto out_free;
                }
 
-               if (unlikely(ccid_hc_rx_init(newdp->dccps_hc_rx_ccid,
-                                            newsk) != 0 ||
-                            ccid_hc_tx_init(newdp->dccps_hc_tx_ccid,
-                                            newsk) != 0)) {
+               newdp->dccps_hc_rx_ccid =
+                           ccid_hc_rx_new(newdmsk->dccpms_rx_ccid,
+                                          newsk, GFP_ATOMIC);
+               newdp->dccps_hc_tx_ccid =
+                           ccid_hc_tx_new(newdmsk->dccpms_tx_ccid,
+                                          newsk, GFP_ATOMIC);
+               if (unlikely(newdp->dccps_hc_rx_ccid == NULL ||
+                            newdp->dccps_hc_tx_ccid == NULL)) {
                        dccp_ackvec_free(newdp->dccps_hc_rx_ackvec);
-                       ccid_hc_rx_exit(newdp->dccps_hc_rx_ccid, newsk);
-                       ccid_hc_tx_exit(newdp->dccps_hc_tx_ccid, newsk);
+                       ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk);
+                       ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk);
 out_free:
                        /* It is still raw copy of parent, so invalidate
                         * destructor and make plain sk_free() */
@@ -143,9 +145,6 @@ out_free:
                        return NULL;
                }
 
-               __ccid_get(newdp->dccps_hc_rx_ccid);
-               __ccid_get(newdp->dccps_hc_tx_ccid);
-
                /*
                 * Step 3: Process LISTEN state
                 *
@@ -155,7 +154,7 @@ out_free:
                 */
 
                /* See dccp_v4_conn_request */
-               newdp->dccps_options.dccpo_sequence_window = req->rcv_wnd;
+               newdmsk->dccpms_sequence_window = req->rcv_wnd;
 
                newdp->dccps_gar = newdp->dccps_isr = dreq->dreq_isr;
                dccp_update_gsr(newsk, dreq->dreq_isr);
index 0a76426..e9feb2a 100644 (file)
 #include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
-/* stores the default values for new connection. may be changed with sysctl */
-static const struct dccp_options dccpo_default_values = {
-       .dccpo_sequence_window    = DCCPF_INITIAL_SEQUENCE_WINDOW,
-       .dccpo_rx_ccid            = DCCPF_INITIAL_CCID,
-       .dccpo_tx_ccid            = DCCPF_INITIAL_CCID,
-       .dccpo_send_ack_vector    = DCCPF_INITIAL_SEND_ACK_VECTOR,
-       .dccpo_send_ndp_count     = DCCPF_INITIAL_SEND_NDP_COUNT,
-};
+int dccp_feat_default_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
+int dccp_feat_default_rx_ccid        = DCCPF_INITIAL_CCID;
+int dccp_feat_default_tx_ccid        = DCCPF_INITIAL_CCID;
+int dccp_feat_default_ack_ratio              = DCCPF_INITIAL_ACK_RATIO;
+int dccp_feat_default_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
+int dccp_feat_default_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
-void dccp_options_init(struct dccp_options *dccpo)
+void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
-       memcpy(dccpo, &dccpo_default_values, sizeof(*dccpo));
+       dmsk->dccpms_sequence_window = dccp_feat_default_sequence_window;
+       dmsk->dccpms_rx_ccid         = dccp_feat_default_rx_ccid;
+       dmsk->dccpms_tx_ccid         = dccp_feat_default_tx_ccid;
+       dmsk->dccpms_ack_ratio       = dccp_feat_default_ack_ratio;
+       dmsk->dccpms_send_ack_vector = dccp_feat_default_send_ack_vector;
+       dmsk->dccpms_send_ndp_count  = dccp_feat_default_send_ndp_count;
 }
 
 static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
@@ -69,9 +73,12 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
        unsigned char opt, len;
        unsigned char *value;
        u32 elapsed_time;
+       int rc;
+       int mandatory = 0;
 
        memset(opt_recv, 0, sizeof(*opt_recv));
 
+       opt = len = 0;
        while (opt_ptr != opt_end) {
                opt   = *opt_ptr++;
                len   = 0;
@@ -100,6 +107,12 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                switch (opt) {
                case DCCPO_PADDING:
                        break;
+               case DCCPO_MANDATORY:
+                       if (mandatory)
+                               goto out_invalid_option;
+                       if (pkt_type != DCCP_PKT_DATA)
+                               mandatory = 1;
+                       break;
                case DCCPO_NDP_COUNT:
                        if (len > 3)
                                goto out_invalid_option;
@@ -108,12 +121,37 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                        dccp_pr_debug("%sNDP count=%d\n", debug_prefix,
                                      opt_recv->dccpor_ndp);
                        break;
+               case DCCPO_CHANGE_L:
+                       /* fall through */
+               case DCCPO_CHANGE_R:
+                       if (len < 2)
+                               goto out_invalid_option;
+                       rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
+                                                  len - 1);
+                       /*
+                        * When there is a change error, change_recv is
+                        * responsible for dealing with it.  i.e. reply with an
+                        * empty confirm.
+                        * If the change was mandatory, then we need to die.
+                        */
+                       if (rc && mandatory)
+                               goto out_invalid_option;
+                       break;
+               case DCCPO_CONFIRM_L:
+                       /* fall through */
+               case DCCPO_CONFIRM_R:
+                       if (len < 2)
+                               goto out_invalid_option;
+                       if (dccp_feat_confirm_recv(sk, opt, *value,
+                                                  value + 1, len - 1))
+                               goto out_invalid_option;
+                       break;
                case DCCPO_ACK_VECTOR_0:
                case DCCPO_ACK_VECTOR_1:
                        if (pkt_type == DCCP_PKT_DATA)
-                               continue;
+                               break;
 
-                       if (dp->dccps_options.dccpo_send_ack_vector &&
+                       if (dccp_msk(sk)->dccpms_send_ack_vector &&
                            dccp_ackvec_parse(sk, skb, opt, value, len))
                                goto out_invalid_option;
                        break;
@@ -121,7 +159,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                        if (len != 4)
                                goto out_invalid_option;
 
-                       opt_recv->dccpor_timestamp = ntohl(*(u32 *)value);
+                       opt_recv->dccpor_timestamp = ntohl(*(__be32 *)value);
 
                        dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp;
                        dccp_timestamp(sk, &dp->dccps_timestamp_time);
@@ -135,7 +173,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                        if (len != 4 && len != 6 && len != 8)
                                goto out_invalid_option;
 
-                       opt_recv->dccpor_timestamp_echo = ntohl(*(u32 *)value);
+                       opt_recv->dccpor_timestamp_echo = ntohl(*(__be32 *)value);
 
                        dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ",
                                      debug_prefix,
@@ -149,9 +187,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                                break;
 
                        if (len == 6)
-                               elapsed_time = ntohs(*(u16 *)(value + 4));
+                               elapsed_time = ntohs(*(__be16 *)(value + 4));
                        else
-                               elapsed_time = ntohl(*(u32 *)(value + 4));
+                               elapsed_time = ntohl(*(__be32 *)(value + 4));
 
                        /* Give precedence to the biggest ELAPSED_TIME */
                        if (elapsed_time > opt_recv->dccpor_elapsed_time)
@@ -165,9 +203,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                                continue;
 
                        if (len == 2)
-                               elapsed_time = ntohs(*(u16 *)value);
+                               elapsed_time = ntohs(*(__be16 *)value);
                        else
-                               elapsed_time = ntohl(*(u32 *)value);
+                               elapsed_time = ntohl(*(__be32 *)value);
 
                        if (elapsed_time > opt_recv->dccpor_elapsed_time)
                                opt_recv->dccpor_elapsed_time = elapsed_time;
@@ -208,8 +246,15 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
                                sk, opt, len);
                        break;
                }
+
+               if (opt != DCCPO_MANDATORY)
+                       mandatory = 0;
        }
 
+       /* mandatory was the last byte in option list -> reset connection */
+       if (mandatory)
+               goto out_invalid_option;
+
        return 0;
 
 out_invalid_option:
@@ -219,6 +264,8 @@ out_invalid_option:
        return -1;
 }
 
+EXPORT_SYMBOL_GPL(dccp_parse_options);
+
 static void dccp_encode_value_var(const u32 value, unsigned char *to,
                                  const unsigned int len)
 {
@@ -237,17 +284,14 @@ static inline int dccp_ndp_len(const int ndp)
        return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3;
 }
 
-void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
+int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
                        const unsigned char option,
                        const void *value, const unsigned char len)
 {
        unsigned char *to;
 
-       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) {
-               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert "
-                              "%d option!\n", option);
-               return;
-       }
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN)
+               return -1;
 
        DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2;
 
@@ -256,11 +300,12 @@ void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
        *to++ = len + 2;
 
        memcpy(to, value, len);
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(dccp_insert_option);
 
-static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
+static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
        int ndp = dp->dccps_ndp_count;
@@ -276,7 +321,7 @@ static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
                const int len = ndp_len + 2;
 
                if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
-                       return;
+                       return -1;
 
                DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
@@ -285,6 +330,8 @@ static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
                *ptr++ = len;
                dccp_encode_value_var(ndp, ptr, ndp_len);
        }
+
+       return 0;
 }
 
 static inline int dccp_elapsed_time_len(const u32 elapsed_time)
@@ -292,27 +339,18 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time)
        return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
 }
 
-void dccp_insert_option_elapsed_time(struct sock *sk,
-                                    struct sk_buff *skb,
-                                    u32 elapsed_time)
+int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb,
+                                   u32 elapsed_time)
 {
-#ifdef CONFIG_IP_DCCP_DEBUG
-       struct dccp_sock *dp = dccp_sk(sk);
-       const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
-                                       "CLIENT TX opt: " : "server TX opt: ";
-#endif
        const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
        const int len = 2 + elapsed_time_len;
        unsigned char *to;
 
        if (elapsed_time_len == 0)
-               return;
+               return 0;
 
-       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
-               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to "
-                                        "insert elapsed time!\n");
-               return;
-       }
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+               return -1;
 
        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
@@ -321,17 +359,14 @@ void dccp_insert_option_elapsed_time(struct sock *sk,
        *to++ = len;
 
        if (elapsed_time_len == 2) {
-               const u16 var16 = htons((u16)elapsed_time);
+               const __be16 var16 = htons((u16)elapsed_time);
                memcpy(to, &var16, 2);
        } else {
-               const u32 var32 = htonl(elapsed_time);
+               const __be32 var32 = htonl(elapsed_time);
                memcpy(to, &var32, 4);
        }
 
-       dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n",
-                     debug_prefix, elapsed_time,
-                     len,
-                     (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
@@ -352,32 +387,27 @@ void dccp_timestamp(const struct sock *sk, struct timeval *tv)
 
 EXPORT_SYMBOL_GPL(dccp_timestamp);
 
-void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
+int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
 {
        struct timeval tv;
-       u32 now;
-       
+       __be32 now;
+
        dccp_timestamp(sk, &tv);
-       now = timeval_usecs(&tv) / 10;
+       now = htonl(timeval_usecs(&tv) / 10);
        /* yes this will overflow but that is the point as we want a
         * 10 usec 32 bit timer which mean it wraps every 11.9 hours */
 
-       now = htonl(now);
-       dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
+       return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
 }
 
 EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
 
-static void dccp_insert_option_timestamp_echo(struct sock *sk,
-                                             struct sk_buff *skb)
+static int dccp_insert_option_timestamp_echo(struct sock *sk,
+                                            struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-#ifdef CONFIG_IP_DCCP_DEBUG
-       const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
-                                       "CLIENT TX opt: " : "server TX opt: ";
-#endif
        struct timeval now;
-       u32 tstamp_echo;
+       __be32 tstamp_echo;
        u32 elapsed_time;
        int len, elapsed_time_len;
        unsigned char *to;
@@ -387,11 +417,8 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk,
        elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
        len = 6 + elapsed_time_len;
 
-       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
-               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert "
-                                        "timestamp echo!\n");
-               return;
-       }
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+               return -1;
 
        DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
@@ -402,51 +429,149 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk,
        tstamp_echo = htonl(dp->dccps_timestamp_echo);
        memcpy(to, &tstamp_echo, 4);
        to += 4;
-       
+
        if (elapsed_time_len == 2) {
-               const u16 var16 = htons((u16)elapsed_time);
+               const __be16 var16 = htons((u16)elapsed_time);
                memcpy(to, &var16, 2);
        } else if (elapsed_time_len == 4) {
-               const u32 var32 = htonl(elapsed_time);
+               const __be32 var32 = htonl(elapsed_time);
                memcpy(to, &var32, 4);
        }
 
-       dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n",
-                     debug_prefix, dp->dccps_timestamp_echo,
-                     len,
-                     (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
-
        dp->dccps_timestamp_echo = 0;
        dp->dccps_timestamp_time.tv_sec = 0;
        dp->dccps_timestamp_time.tv_usec = 0;
+       return 0;
 }
 
-void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
+static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
+                               u8 *val, u8 len)
+{
+       u8 *to;
+
+       if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
+               LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small"
+                              " to insert feature %d option!\n", feat);
+               return -1;
+       }
+
+       DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
+
+       to    = skb_push(skb, len + 3);
+       *to++ = type;
+       *to++ = len + 3;
+       *to++ = feat;
+
+       if (len)
+               memcpy(to, val, len);
+       dccp_pr_debug("option %d feat %d len %d\n", type, feat, len);
+
+       return 0;
+}
+
+static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+       struct dccp_opt_pend *opt, *next;
+       int change = 0;
+
+       /* confirm any options [NN opts] */
+       list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
+               dccp_insert_feat_opt(skb, opt->dccpop_type,
+                                    opt->dccpop_feat, opt->dccpop_val,
+                                    opt->dccpop_len);
+               /* fear empty confirms */
+               if (opt->dccpop_val)
+                       kfree(opt->dccpop_val);
+               kfree(opt);
+       }
+       INIT_LIST_HEAD(&dmsk->dccpms_conf);
+
+       /* see which features we need to send */
+       list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
+               /* see if we need to send any confirm */
+               if (opt->dccpop_sc) {
+                       dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
+                                            opt->dccpop_feat,
+                                            opt->dccpop_sc->dccpoc_val,
+                                            opt->dccpop_sc->dccpoc_len);
+
+                       BUG_ON(!opt->dccpop_sc->dccpoc_val);
+                       kfree(opt->dccpop_sc->dccpoc_val);
+                       kfree(opt->dccpop_sc);
+                       opt->dccpop_sc = NULL;
+               }
+
+               /* any option not confirmed, re-send it */
+               if (!opt->dccpop_conf) {
+                       dccp_insert_feat_opt(skb, opt->dccpop_type,
+                                            opt->dccpop_feat, opt->dccpop_val,
+                                            opt->dccpop_len);
+                       change++;
+               }
+       }
+
+       /* Retransmit timer.
+        * If this is the master listening sock, we don't set a timer on it.  It
+        * should be fine because if the dude doesn't receive our RESPONSE
+        * [which will contain the CHANGE] he will send another REQUEST which
+        * will "retrnasmit" the change.
+        */
+       if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
+               dccp_pr_debug("reset feat negotiation timer %p\n", sk);
+
+               /* XXX don't reset the timer on re-transmissions.  I.e. reset it
+                * only when sending new stuff i guess.  Currently the timer
+                * never backs off because on re-transmission it just resets it!
+                */
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                         inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
+       }
+
+       return 0;
+}
+
+int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
 
        DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
-       if (dp->dccps_options.dccpo_send_ndp_count)
-               dccp_insert_option_ndp(sk, skb);
+       if (dmsk->dccpms_send_ndp_count &&
+           dccp_insert_option_ndp(sk, skb))
+               return -1;
 
        if (!dccp_packet_without_ack(skb)) {
-               if (dp->dccps_options.dccpo_send_ack_vector &&
-                   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec))
-                       dccp_insert_option_ackvec(sk, skb);
-               if (dp->dccps_timestamp_echo != 0)
-                       dccp_insert_option_timestamp_echo(sk, skb);
+               if (dmsk->dccpms_send_ack_vector &&
+                   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
+                   dccp_insert_option_ackvec(sk, skb))
+                       return -1;
+
+               if (dp->dccps_timestamp_echo != 0 &&
+                   dccp_insert_option_timestamp_echo(sk, skb))
+                       return -1;
        }
 
        if (dp->dccps_hc_rx_insert_options) {
-               ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb);
+               if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb))
+                       return -1;
                dp->dccps_hc_rx_insert_options = 0;
        }
        if (dp->dccps_hc_tx_insert_options) {
-               ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb);
+               if (ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb))
+                       return -1;
                dp->dccps_hc_tx_insert_options = 0;
        }
 
+       /* Feature negotiation */
+       /* Data packets can't do feat negotiation */
+       if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
+           DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
+           dccp_insert_options_feat(sk, skb))
+               return -1;
+
        /* XXX: insert other options when appropriate */
 
        if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) {
@@ -459,4 +584,6 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
                        DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
                }
        }
+
+       return 0;
 }
index efd7ffb..7409e4a 100644 (file)
@@ -27,7 +27,7 @@ static inline void dccp_event_ack_sent(struct sock *sk)
        inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
 }
 
-static inline void dccp_skb_entail(struct sock *sk, struct sk_buff *skb)
+static void dccp_skb_entail(struct sock *sk, struct sk_buff *skb)
 {
        skb_set_owner_w(skb, sk);
        WARN_ON(sk->sk_send_head);
@@ -49,7 +49,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
                struct dccp_hdr *dh;
                /* XXX For now we're using only 48 bits sequence numbers */
-               const int dccp_header_size = sizeof(*dh) +
+               const u32 dccp_header_size = sizeof(*dh) +
                                             sizeof(struct dccp_hdr_ext) +
                                          dccp_packet_hdr_len(dcb->dccpd_type);
                int err, set_ack = 1;
@@ -64,6 +64,10 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                case DCCP_PKT_DATAACK:
                        break;
 
+               case DCCP_PKT_REQUEST:
+                       set_ack = 0;
+                       /* fall through */
+
                case DCCP_PKT_SYNC:
                case DCCP_PKT_SYNCACK:
                        ackno = dcb->dccpd_seq;
@@ -79,7 +83,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                }
 
                dcb->dccpd_seq = dp->dccps_gss;
-               dccp_insert_options(sk, skb);
+
+               if (dccp_insert_options(sk, skb)) {
+                       kfree_skb(skb);
+                       return -EPROTO;
+               }
                
                skb->h.raw = skb_push(skb, dccp_header_size);
                dh = dccp_hdr(skb);
@@ -275,17 +283,16 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 {
        struct dccp_hdr *dh;
        struct dccp_request_sock *dreq;
-       const int dccp_header_size = sizeof(struct dccp_hdr) +
+       const u32 dccp_header_size = sizeof(struct dccp_hdr) +
                                     sizeof(struct dccp_hdr_ext) +
                                     sizeof(struct dccp_hdr_response);
-       struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN +
-                                              dccp_header_size, 1,
+       struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1,
                                           GFP_ATOMIC);
        if (skb == NULL)
                return NULL;
 
        /* Reserve space for headers. */
-       skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size);
+       skb_reserve(skb, sk->sk_prot->max_header);
 
        skb->dst = dst_clone(dst);
        skb->csum = 0;
@@ -293,7 +300,11 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
        dreq = dccp_rsk(req);
        DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
        DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
-       dccp_insert_options(sk, skb);
+
+       if (dccp_insert_options(sk, skb)) {
+               kfree_skb(skb);
+               return NULL;
+       }
 
        skb->h.raw = skb_push(skb, dccp_header_size);
 
@@ -310,32 +321,28 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
        dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr);
        dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service;
 
-       dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr,
-                                             inet_rsk(req)->rmt_addr);
-
        DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
        return skb;
 }
 
 EXPORT_SYMBOL_GPL(dccp_make_response);
 
-struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
-                               const enum dccp_reset_codes code)
+static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
+                                      const enum dccp_reset_codes code)
                                   
 {
        struct dccp_hdr *dh;
        struct dccp_sock *dp = dccp_sk(sk);
-       const int dccp_header_size = sizeof(struct dccp_hdr) +
+       const u32 dccp_header_size = sizeof(struct dccp_hdr) +
                                     sizeof(struct dccp_hdr_ext) +
                                     sizeof(struct dccp_hdr_reset);
-       struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN +
-                                              dccp_header_size, 1,
+       struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1,
                                           GFP_ATOMIC);
        if (skb == NULL)
                return NULL;
 
        /* Reserve space for headers. */
-       skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size);
+       skb_reserve(skb, sk->sk_prot->max_header);
 
        skb->dst = dst_clone(dst);
        skb->csum = 0;
@@ -345,7 +352,11 @@ struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
        DCCP_SKB_CB(skb)->dccpd_reset_code = code;
        DCCP_SKB_CB(skb)->dccpd_type       = DCCP_PKT_RESET;
        DCCP_SKB_CB(skb)->dccpd_seq        = dp->dccps_gss;
-       dccp_insert_options(sk, skb);
+
+       if (dccp_insert_options(sk, skb)) {
+               kfree_skb(skb);
+               return NULL;
+       }
 
        skb->h.raw = skb_push(skb, dccp_header_size);
 
@@ -362,14 +373,34 @@ struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
        dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr);
 
        dccp_hdr_reset(skb)->dccph_reset_code = code;
-
-       dh->dccph_checksum = dccp_v4_checksum(skb, inet_sk(sk)->saddr,
-                                             inet_sk(sk)->daddr);
+       inet_csk(sk)->icsk_af_ops->send_check(sk, skb->len, skb);
 
        DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
        return skb;
 }
 
+int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code)
+{
+       /*
+        * FIXME: what if rebuild_header fails?
+        * Should we be doing a rebuild_header here?
+        */
+       int err = inet_sk_rebuild_header(sk);
+
+       if (err == 0) {
+               struct sk_buff *skb = dccp_make_reset(sk, sk->sk_dst_cache,
+                                                     code);
+               if (skb != NULL) {
+                       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+                       err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, 0);
+                       if (err == NET_XMIT_CN)
+                               err = 0;
+               }
+       }
+
+       return err;
+}
+
 /*
  * Do all connect socket setups that can be done AF independent.
  */
@@ -405,12 +436,12 @@ int dccp_connect(struct sock *sk)
 
        dccp_connect_init(sk);
 
-       skb = alloc_skb(MAX_DCCP_HEADER + 15, sk->sk_allocation);
+       skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
        if (unlikely(skb == NULL))
                return -ENOBUFS;
 
        /* Reserve space for headers. */
-       skb_reserve(skb, MAX_DCCP_HEADER);
+       skb_reserve(skb, sk->sk_prot->max_header);
 
        DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST;
        skb->csum = 0;
@@ -431,7 +462,8 @@ void dccp_send_ack(struct sock *sk)
 {
        /* If we have been reset, we may not send again. */
        if (sk->sk_state != DCCP_CLOSED) {
-               struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC);
+               struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header,
+                                               GFP_ATOMIC);
 
                if (skb == NULL) {
                        inet_csk_schedule_ack(sk);
@@ -443,7 +475,7 @@ void dccp_send_ack(struct sock *sk)
                }
 
                /* Reserve space for headers */
-               skb_reserve(skb, MAX_DCCP_HEADER);
+               skb_reserve(skb, sk->sk_prot->max_header);
                skb->csum = 0;
                DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK;
                dccp_transmit_skb(sk, skb);
@@ -490,14 +522,14 @@ void dccp_send_sync(struct sock *sk, const u64 seq,
         * dccp_transmit_skb() will set the ownership to this
         * sock.
         */
-       struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC);
+       struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header, GFP_ATOMIC);
 
        if (skb == NULL)
                /* FIXME: how to make sure the sync is sent? */
                return;
 
        /* Reserve space for headers and prepare control bits. */
-       skb_reserve(skb, MAX_DCCP_HEADER);
+       skb_reserve(skb, sk->sk_prot->max_header);
        skb->csum = 0;
        DCCP_SKB_CB(skb)->dccpd_type = pkt_type;
        DCCP_SKB_CB(skb)->dccpd_seq = seq;
@@ -505,6 +537,8 @@ void dccp_send_sync(struct sock *sk, const u64 seq,
        dccp_transmit_skb(sk, skb);
 }
 
+EXPORT_SYMBOL_GPL(dccp_send_sync);
+
 /*
  * Send a DCCP_PKT_CLOSE/CLOSEREQ. The caller locks the socket for us. This
  * cannot be allowed to fail queueing a DCCP_PKT_CLOSE/CLOSEREQ frame under
index 65b11ea..d4b293e 100644 (file)
@@ -23,9 +23,7 @@
 #include <linux/random.h>
 #include <net/checksum.h>
 
-#include <net/inet_common.h>
 #include <net/inet_sock.h>
-#include <net/protocol.h>
 #include <net/sock.h>
 #include <net/xfrm.h>
 
@@ -37,6 +35,7 @@
 
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
 DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
 
@@ -46,12 +45,66 @@ atomic_t dccp_orphan_count = ATOMIC_INIT(0);
 
 EXPORT_SYMBOL_GPL(dccp_orphan_count);
 
-static struct net_protocol dccp_protocol = {
-       .handler        = dccp_v4_rcv,
-       .err_handler    = dccp_v4_err,
-       .no_policy      = 1,
+struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
+       .lhash_lock     = RW_LOCK_UNLOCKED,
+       .lhash_users    = ATOMIC_INIT(0),
+       .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
 };
 
+EXPORT_SYMBOL_GPL(dccp_hashinfo);
+
+void dccp_set_state(struct sock *sk, const int state)
+{
+       const int oldstate = sk->sk_state;
+
+       dccp_pr_debug("%s(%p) %-10.10s -> %s\n",
+                     dccp_role(sk), sk,
+                     dccp_state_name(oldstate), dccp_state_name(state));
+       WARN_ON(state == oldstate);
+
+       switch (state) {
+       case DCCP_OPEN:
+               if (oldstate != DCCP_OPEN)
+                       DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
+               break;
+
+       case DCCP_CLOSED:
+               if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN)
+                       DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
+
+               sk->sk_prot->unhash(sk);
+               if (inet_csk(sk)->icsk_bind_hash != NULL &&
+                   !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
+                       inet_put_port(&dccp_hashinfo, sk);
+               /* fall through */
+       default:
+               if (oldstate == DCCP_OPEN)
+                       DCCP_DEC_STATS(DCCP_MIB_CURRESTAB);
+       }
+
+       /* Change state AFTER socket is unhashed to avoid closed
+        * socket sitting in hash tables.
+        */
+       sk->sk_state = state;
+}
+
+EXPORT_SYMBOL_GPL(dccp_set_state);
+
+void dccp_done(struct sock *sk)
+{
+       dccp_set_state(sk, DCCP_CLOSED);
+       dccp_clear_xmit_timers(sk);
+
+       sk->sk_shutdown = SHUTDOWN_MASK;
+
+       if (!sock_flag(sk, SOCK_DEAD))
+               sk->sk_state_change(sk);
+       else
+               inet_csk_destroy_sock(sk);
+}
+
+EXPORT_SYMBOL_GPL(dccp_done);
+
 const char *dccp_packet_name(const int type)
 {
        static const char *dccp_packet_names[] = {
@@ -96,6 +149,120 @@ const char *dccp_state_name(const int state)
 
 EXPORT_SYMBOL_GPL(dccp_state_name);
 
+void dccp_hash(struct sock *sk)
+{
+       inet_hash(&dccp_hashinfo, sk);
+}
+
+EXPORT_SYMBOL_GPL(dccp_hash);
+
+void dccp_unhash(struct sock *sk)
+{
+       inet_unhash(&dccp_hashinfo, sk);
+}
+
+EXPORT_SYMBOL_GPL(dccp_unhash);
+
+int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       dccp_minisock_init(&dp->dccps_minisock);
+       do_gettimeofday(&dp->dccps_epoch);
+
+       /*
+        * FIXME: We're hardcoding the CCID, and doing this at this point makes
+        * the listening (master) sock get CCID control blocks, which is not
+        * necessary, but for now, to not mess with the test userspace apps,
+        * lets leave it here, later the real solution is to do this in a
+        * setsockopt(CCIDs-I-want/accept). -acme
+        */
+       if (likely(ctl_sock_initialized)) {
+               int rc = dccp_feat_init(dmsk);
+
+               if (rc)
+                       return rc;
+
+               if (dmsk->dccpms_send_ack_vector) {
+                       dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
+                       if (dp->dccps_hc_rx_ackvec == NULL)
+                               return -ENOMEM;
+               }
+               dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
+                                                     sk, GFP_KERNEL);
+               dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
+                                                     sk, GFP_KERNEL);
+               if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
+                            dp->dccps_hc_tx_ccid == NULL)) {
+                       ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+                       ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+                       if (dmsk->dccpms_send_ack_vector) {
+                               dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+                               dp->dccps_hc_rx_ackvec = NULL;
+                       }
+                       dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+                       return -ENOMEM;
+               }
+       } else {
+               /* control socket doesn't need feat nego */
+               INIT_LIST_HEAD(&dmsk->dccpms_pending);
+               INIT_LIST_HEAD(&dmsk->dccpms_conf);
+       }
+
+       dccp_init_xmit_timers(sk);
+       icsk->icsk_rto          = DCCP_TIMEOUT_INIT;
+       sk->sk_state            = DCCP_CLOSED;
+       sk->sk_write_space      = dccp_write_space;
+       icsk->icsk_sync_mss     = dccp_sync_mss;
+       dp->dccps_mss_cache     = 536;
+       dp->dccps_role          = DCCP_ROLE_UNDEFINED;
+       dp->dccps_service       = DCCP_SERVICE_INVALID_VALUE;
+       dp->dccps_l_ack_ratio   = dp->dccps_r_ack_ratio = 1;
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(dccp_init_sock);
+
+int dccp_destroy_sock(struct sock *sk)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_minisock *dmsk = dccp_msk(sk);
+
+       /*
+        * DCCP doesn't use sk_write_queue, just sk_send_head
+        * for retransmissions
+        */
+       if (sk->sk_send_head != NULL) {
+               kfree_skb(sk->sk_send_head);
+               sk->sk_send_head = NULL;
+       }
+
+       /* Clean up a referenced DCCP bind bucket. */
+       if (inet_csk(sk)->icsk_bind_hash != NULL)
+               inet_put_port(&dccp_hashinfo, sk);
+
+       kfree(dp->dccps_service_list);
+       dp->dccps_service_list = NULL;
+
+       if (dmsk->dccpms_send_ack_vector) {
+               dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+               dp->dccps_hc_rx_ackvec = NULL;
+       }
+       ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+       ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+       dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+
+       /* clean up feature negotiation state */
+       dccp_feat_clean(dmsk);
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(dccp_destroy_sock);
+
 static inline int dccp_listen_start(struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
@@ -220,7 +387,7 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 
 EXPORT_SYMBOL_GPL(dccp_ioctl);
 
-static int dccp_setsockopt_service(struct sock *sk, const u32 service,
+static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
                                   char __user *optval, int optlen)
 {
        struct dccp_sock *dp = dccp_sk(sk);
@@ -255,18 +422,46 @@ static int dccp_setsockopt_service(struct sock *sk, const u32 service,
        return 0;
 }
 
-int dccp_setsockopt(struct sock *sk, int level, int optname,
-                   char __user *optval, int optlen)
+/* byte 1 is feature.  the rest is the preference list */
+static int dccp_setsockopt_change(struct sock *sk, int type,
+                                 struct dccp_so_feat __user *optval)
+{
+       struct dccp_so_feat opt;
+       u8 *val;
+       int rc;
+
+       if (copy_from_user(&opt, optval, sizeof(opt)))
+               return -EFAULT;
+
+       val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
+       if (!val)
+               return -ENOMEM;
+
+       if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
+               rc = -EFAULT;
+               goto out_free_val;
+       }
+
+       rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
+                             val, opt.dccpsf_len, GFP_KERNEL);
+       if (rc)
+               goto out_free_val;
+
+out:
+       return rc;
+
+out_free_val:
+       kfree(val);
+       goto out;
+}
+
+static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
+               char __user *optval, int optlen)
 {
        struct dccp_sock *dp;
        int err;
        int val;
 
-       if (level != SOL_DCCP)
-               return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
-                                                            optname, optval,
-                                                            optlen);
-
        if (optlen < sizeof(int))
                return -EINVAL;
 
@@ -284,6 +479,25 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
        case DCCP_SOCKOPT_PACKET_SIZE:
                dp->dccps_packet_size = val;
                break;
+
+       case DCCP_SOCKOPT_CHANGE_L:
+               if (optlen != sizeof(struct dccp_so_feat))
+                       err = -EINVAL;
+               else
+                       err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
+                                                    (struct dccp_so_feat *)
+                                                    optval);
+               break;
+
+       case DCCP_SOCKOPT_CHANGE_R:
+               if (optlen != sizeof(struct dccp_so_feat))
+                       err = -EINVAL;
+               else
+                       err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
+                                                    (struct dccp_so_feat *)
+                                                    optval);
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -293,10 +507,33 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
        return err;
 }
 
+int dccp_setsockopt(struct sock *sk, int level, int optname,
+                   char __user *optval, int optlen)
+{
+       if (level != SOL_DCCP)
+               return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
+                                                            optname, optval,
+                                                            optlen);
+       return do_dccp_setsockopt(sk, level, optname, optval, optlen);
+}
+
 EXPORT_SYMBOL_GPL(dccp_setsockopt);
 
+#ifdef CONFIG_COMPAT
+int compat_dccp_setsockopt(struct sock *sk, int level, int optname,
+                          char __user *optval, int optlen)
+{
+       if (level != SOL_DCCP)
+               return inet_csk_compat_setsockopt(sk, level, optname,
+                                                 optval, optlen);
+       return do_dccp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(compat_dccp_setsockopt);
+#endif
+
 static int dccp_getsockopt_service(struct sock *sk, int len,
-                                  u32 __user *optval,
+                                  __be32 __user *optval,
                                   int __user *optlen)
 {
        const struct dccp_sock *dp = dccp_sk(sk);
@@ -326,16 +563,12 @@ out:
        return err;
 }
 
-int dccp_getsockopt(struct sock *sk, int level, int optname,
+static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int __user *optlen)
 {
        struct dccp_sock *dp;
        int val, len;
 
-       if (level != SOL_DCCP)
-               return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
-                                                            optname, optval,
-                                                            optlen);
        if (get_user(len, optlen))
                return -EFAULT;
 
@@ -351,7 +584,7 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
                break;
        case DCCP_SOCKOPT_SERVICE:
                return dccp_getsockopt_service(sk, len,
-                                              (u32 __user *)optval, optlen);
+                                              (__be32 __user *)optval, optlen);
        case 128 ... 191:
                return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
                                             len, (u32 __user *)optval, optlen);
@@ -368,8 +601,31 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
        return 0;
 }
 
+int dccp_getsockopt(struct sock *sk, int level, int optname,
+                   char __user *optval, int __user *optlen)
+{
+       if (level != SOL_DCCP)
+               return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
+                                                            optname, optval,
+                                                            optlen);
+       return do_dccp_getsockopt(sk, level, optname, optval, optlen);
+}
+
 EXPORT_SYMBOL_GPL(dccp_getsockopt);
 
+#ifdef CONFIG_COMPAT
+int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
+                          char __user *optval, int __user *optlen)
+{
+       if (level != SOL_DCCP)
+               return inet_csk_compat_getsockopt(sk, level, optname,
+                                                 optval, optlen);
+       return do_dccp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
+#endif
+
 int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                 size_t len)
 {
@@ -679,84 +935,7 @@ void dccp_shutdown(struct sock *sk, int how)
 
 EXPORT_SYMBOL_GPL(dccp_shutdown);
 
-static const struct proto_ops inet_dccp_ops = {
-       .family         = PF_INET,
-       .owner          = THIS_MODULE,
-       .release        = inet_release,
-       .bind           = inet_bind,
-       .connect        = inet_stream_connect,
-       .socketpair     = sock_no_socketpair,
-       .accept         = inet_accept,
-       .getname        = inet_getname,
-       /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
-       .poll           = dccp_poll,
-       .ioctl          = inet_ioctl,
-       /* FIXME: work on inet_listen to rename it to sock_common_listen */
-       .listen         = inet_dccp_listen,
-       .shutdown       = inet_shutdown,
-       .setsockopt     = sock_common_setsockopt,
-       .getsockopt     = sock_common_getsockopt,
-       .sendmsg        = inet_sendmsg,
-       .recvmsg        = sock_common_recvmsg,
-       .mmap           = sock_no_mmap,
-       .sendpage       = sock_no_sendpage,
-};
-
-extern struct net_proto_family inet_family_ops;
-
-static struct inet_protosw dccp_v4_protosw = {
-       .type           = SOCK_DCCP,
-       .protocol       = IPPROTO_DCCP,
-       .prot           = &dccp_prot,
-       .ops            = &inet_dccp_ops,
-       .capability     = -1,
-       .no_check       = 0,
-       .flags          = INET_PROTOSW_ICSK,
-};
-
-/*
- * This is the global socket data structure used for responding to
- * the Out-of-the-blue (OOTB) packets. A control sock will be created
- * for this socket at the initialization time.
- */
-struct socket *dccp_ctl_socket;
-
-static char dccp_ctl_socket_err_msg[] __initdata =
-       KERN_ERR "DCCP: Failed to create the control socket.\n";
-
-static int __init dccp_ctl_sock_init(void)
-{
-       int rc = sock_create_kern(PF_INET, SOCK_DCCP, IPPROTO_DCCP,
-                                 &dccp_ctl_socket);
-       if (rc < 0)
-               printk(dccp_ctl_socket_err_msg);
-       else {
-               dccp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
-               inet_sk(dccp_ctl_socket->sk)->uc_ttl = -1;
-
-               /* Unhash it so that IP input processing does not even
-                * see it, we do not wish this socket to see incoming
-                * packets.
-                */
-               dccp_ctl_socket->sk->sk_prot->unhash(dccp_ctl_socket->sk);
-       }
-
-       return rc;
-}
-
-#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
-void dccp_ctl_sock_exit(void)
-{
-       if (dccp_ctl_socket != NULL) {
-               sock_release(dccp_ctl_socket);
-               dccp_ctl_socket = NULL;
-       }
-}
-
-EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit);
-#endif
-
-static int __init init_dccp_v4_mibs(void)
+static int __init dccp_mib_init(void)
 {
        int rc = -ENOMEM;
 
@@ -778,6 +957,13 @@ out_free_one:
 
 }
 
+static void dccp_mib_exit(void)
+{
+       free_percpu(dccp_statistics[0]);
+       free_percpu(dccp_statistics[1]);
+       dccp_statistics[0] = dccp_statistics[1] = NULL;
+}
+
 static int thash_entries;
 module_param(thash_entries, int, 0444);
 MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
@@ -794,17 +980,14 @@ static int __init dccp_init(void)
 {
        unsigned long goal;
        int ehash_order, bhash_order, i;
-       int rc = proto_register(&dccp_prot, 1);
-
-       if (rc)
-               goto out;
+       int rc = -ENOBUFS;
 
        dccp_hashinfo.bind_bucket_cachep =
                kmem_cache_create("dccp_bind_bucket",
                                  sizeof(struct inet_bind_bucket), 0,
                                  SLAB_HWCACHE_ALIGN, NULL, NULL);
        if (!dccp_hashinfo.bind_bucket_cachep)
-               goto out_proto_unregister;
+               goto out;
 
        /*
         * Size and allocate the main established and bind bucket
@@ -866,27 +1049,23 @@ static int __init dccp_init(void)
                INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
        }
 
-       if (init_dccp_v4_mibs())
+       rc = dccp_mib_init();
+       if (rc)
                goto out_free_dccp_bhash;
 
-       rc = -EAGAIN;
-       if (inet_add_protocol(&dccp_protocol, IPPROTO_DCCP))
-               goto out_free_dccp_v4_mibs;
-
-       inet_register_protosw(&dccp_v4_protosw);
+       rc = dccp_ackvec_init();
+       if (rc)
+               goto out_free_dccp_mib;
 
-       rc = dccp_ctl_sock_init();
+       rc = dccp_sysctl_init();
        if (rc)
-               goto out_unregister_protosw;
+               goto out_ackvec_exit;
 out:
        return rc;
-out_unregister_protosw:
-       inet_unregister_protosw(&dccp_v4_protosw);
-       inet_del_protocol(&dccp_protocol, IPPROTO_DCCP);
-out_free_dccp_v4_mibs:
-       free_percpu(dccp_statistics[0]);
-       free_percpu(dccp_statistics[1]);
-       dccp_statistics[0] = dccp_statistics[1] = NULL;
+out_ackvec_exit:
+       dccp_ackvec_exit();
+out_free_dccp_mib:
+       dccp_mib_exit();
 out_free_dccp_bhash:
        free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order);
        dccp_hashinfo.bhash = NULL;
@@ -896,23 +1075,12 @@ out_free_dccp_ehash:
 out_free_bind_bucket_cachep:
        kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
        dccp_hashinfo.bind_bucket_cachep = NULL;
-out_proto_unregister:
-       proto_unregister(&dccp_prot);
        goto out;
 }
 
-static const char dccp_del_proto_err_msg[] __exitdata =
-       KERN_ERR "can't remove dccp net_protocol\n";
-
 static void __exit dccp_fini(void)
 {
-       inet_unregister_protosw(&dccp_v4_protosw);
-
-       if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0)
-               printk(dccp_del_proto_err_msg);
-
-       free_percpu(dccp_statistics[0]);
-       free_percpu(dccp_statistics[1]);
+       dccp_mib_exit();
        free_pages((unsigned long)dccp_hashinfo.bhash,
                   get_order(dccp_hashinfo.bhash_size *
                             sizeof(struct inet_bind_hashbucket)));
@@ -920,19 +1088,13 @@ static void __exit dccp_fini(void)
                   get_order(dccp_hashinfo.ehash_size *
                             sizeof(struct inet_ehash_bucket)));
        kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
-       proto_unregister(&dccp_prot);
+       dccp_ackvec_exit();
+       dccp_sysctl_exit();
 }
 
 module_init(dccp_init);
 module_exit(dccp_fini);
 
-/*
- * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
- * values directly, Also cover the case where the protocol is not specified,
- * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
- */
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
 MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c
new file mode 100644 (file)
index 0000000..64c89e9
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *  net/dccp/sysctl.c
+ *
+ *  An implementation of the DCCP protocol
+ *  Arnaldo Carvalho de Melo <acme@mandriva.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License v2
+ *     as published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+#ifndef CONFIG_SYSCTL
+#error This file should not be compiled without CONFIG_SYSCTL defined
+#endif
+
+extern int dccp_feat_default_sequence_window;
+extern int dccp_feat_default_rx_ccid;
+extern int dccp_feat_default_tx_ccid;
+extern int dccp_feat_default_ack_ratio;
+extern int dccp_feat_default_send_ack_vector;
+extern int dccp_feat_default_send_ndp_count;
+
+static struct ctl_table dccp_default_table[] = {
+       {
+               .ctl_name       = NET_DCCP_DEFAULT_SEQ_WINDOW,
+               .procname       = "seq_window",
+               .data           = &dccp_feat_default_sequence_window,
+               .maxlen         = sizeof(dccp_feat_default_sequence_window),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .ctl_name       = NET_DCCP_DEFAULT_RX_CCID,
+               .procname       = "rx_ccid",
+               .data           = &dccp_feat_default_rx_ccid,
+               .maxlen         = sizeof(dccp_feat_default_rx_ccid),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .ctl_name       = NET_DCCP_DEFAULT_TX_CCID,
+               .procname       = "tx_ccid",
+               .data           = &dccp_feat_default_tx_ccid,
+               .maxlen         = sizeof(dccp_feat_default_tx_ccid),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .ctl_name       = NET_DCCP_DEFAULT_ACK_RATIO,
+               .procname       = "ack_ratio",
+               .data           = &dccp_feat_default_ack_ratio,
+               .maxlen         = sizeof(dccp_feat_default_ack_ratio),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .ctl_name       = NET_DCCP_DEFAULT_SEND_ACKVEC,
+               .procname       = "send_ackvec",
+               .data           = &dccp_feat_default_send_ack_vector,
+               .maxlen         = sizeof(dccp_feat_default_send_ack_vector),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .ctl_name       = NET_DCCP_DEFAULT_SEND_NDP,
+               .procname       = "send_ndp",
+               .data           = &dccp_feat_default_send_ndp_count,
+               .maxlen         = sizeof(dccp_feat_default_send_ndp_count),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       { .ctl_name = 0, }
+};
+
+static struct ctl_table dccp_table[] = {
+       {
+               .ctl_name       = NET_DCCP_DEFAULT,
+               .procname       = "default",
+               .mode           = 0555,
+               .child          = dccp_default_table,
+       },
+       { .ctl_name = 0, },
+};
+
+static struct ctl_table dccp_dir_table[] = {
+       {
+               .ctl_name       = NET_DCCP,
+               .procname       = "dccp",
+               .mode           = 0555,
+               .child          = dccp_table,
+       },
+       { .ctl_name = 0, },
+};
+
+static struct ctl_table dccp_root_table[] = {
+       {
+               .ctl_name       = CTL_NET,
+               .procname       = "net",
+               .mode           = 0555,
+               .child          = dccp_dir_table,
+       },
+       { .ctl_name = 0, },
+};
+
+static struct ctl_table_header *dccp_table_header;
+
+int __init dccp_sysctl_init(void)
+{
+       dccp_table_header = register_sysctl_table(dccp_root_table, 1);
+
+       return dccp_table_header != NULL ? 0 : -ENOMEM;
+}
+
+void dccp_sysctl_exit(void)
+{
+       if (dccp_table_header != NULL) {
+               unregister_sysctl_table(dccp_table_header);
+               dccp_table_header = NULL;
+       }
+}
index aa34b57..5244415 100644 (file)
@@ -31,7 +31,7 @@ static void dccp_write_err(struct sock *sk)
        sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
        sk->sk_error_report(sk);
 
-       dccp_v4_send_reset(sk, DCCP_RESET_CODE_ABORTED);
+       dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED);
        dccp_done(sk);
        DCCP_INC_STATS_BH(DCCP_MIB_ABORTONTIMEOUT);
 }
@@ -141,6 +141,17 @@ static void dccp_retransmit_timer(struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
 
+       /* retransmit timer is used for feature negotiation throughout
+        * connection.  In this case, no packet is re-transmitted, but rather an
+        * ack is generated and pending changes are splaced into its options.
+        */
+       if (sk->sk_send_head == NULL) {
+               dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
+               if (sk->sk_state == DCCP_OPEN)
+                       dccp_send_ack(sk);
+               goto backoff;
+       }
+
        /*
         * sk->sk_send_head has to have one skb with
         * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP
@@ -177,6 +188,7 @@ static void dccp_retransmit_timer(struct sock *sk)
                goto out;
        }
 
+backoff:
        icsk->icsk_backoff++;
        icsk->icsk_retransmits++;
 
index ce4aaf9..2b289ef 100644 (file)
@@ -172,7 +172,7 @@ static struct hlist_head *dn_find_list(struct sock *sk)
 /* 
  * Valid ports are those greater than zero and not already in use.
  */
-static int check_port(unsigned short port)
+static int check_port(__le16 port)
 {
        struct sock *sk;
        struct hlist_node *node;
@@ -661,7 +661,7 @@ disc_reject:
        }
 }
 
-char *dn_addr2asc(dn_address addr, char *buf)
+char *dn_addr2asc(__u16 addr, char *buf)
 {
        unsigned short node, area;
 
@@ -801,7 +801,7 @@ static int dn_auto_bind(struct socket *sock)
        /* End of compatibility stuff */
 
        scp->addr.sdn_add.a_len = dn_htons(2);
-       rv = dn_dev_bind_default((dn_address *)scp->addr.sdn_add.a_addr);
+       rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr);
        if (rv == 0) {
                rv = dn_hash_sock(sk);
                if (rv)
@@ -1021,7 +1021,7 @@ static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt)
         opt->opt_optl   = *ptr++;
         opt->opt_status = 0;
         memcpy(opt->opt_data, ptr, opt->opt_optl);
-        skb_pull(skb, opt->opt_optl + 1);
+        skb_pull(skb, dn_ntohs(opt->opt_optl) + 1);
 
 }
 
@@ -1121,8 +1121,8 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
 
        skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type));
        skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type));
-       *(dn_address *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;
-       *(dn_address *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst;
+       *(__le16 *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;
+       *(__le16 *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst;
 
        menuver = *skb->data;
        skb_pull(skb, 1);
@@ -1365,7 +1365,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                        if (optlen != sizeof(struct optdata_dn))
                                return -EINVAL;
 
-                       if (u.opt.opt_optl > 16)
+                       if (dn_ntohs(u.opt.opt_optl) > 16)
                                return -EINVAL;
 
                        memcpy(&scp->conndata_out, &u.opt, optlen);
@@ -1378,7 +1378,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                        if (optlen != sizeof(struct optdata_dn))
                                return -EINVAL;
 
-                       if (u.opt.opt_optl > 16)
+                       if (dn_ntohs(u.opt.opt_optl) > 16)
                                return -EINVAL;
 
                        memcpy(&scp->discdata_out, &u.opt, optlen);
@@ -1693,7 +1693,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (rv)
                goto out;
 
-       if (flags & ~(MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) {
+       if (flags & ~(MSG_CMSG_COMPAT|MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) {
                rv = -EOPNOTSUPP;
                goto out;
        }
index efbead8..cc7b9d9 100644 (file)
@@ -64,7 +64,7 @@ extern struct neigh_table dn_neigh_table;
 /*
  * decnet_address is kept in network order.
  */
-dn_address decnet_address = 0;
+__le16 decnet_address = 0;
 
 static DEFINE_RWLOCK(dndev_lock);
 static struct net_device *decnet_default_device;
@@ -439,7 +439,7 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de
        *ifap = ifa1->ifa_next;
 
        if (dn_db->dev->type == ARPHRD_ETHER) {
-               if (ifa1->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
+               if (ifa1->ifa_local != dn_eth2dn(dev->dev_addr)) {
                        dn_dn2eth(mac_addr, ifa1->ifa_local);
                        dev_mc_delete(dev, mac_addr, ETH_ALEN, 0);
                }
@@ -470,7 +470,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
        }
 
        if (dev->type == ARPHRD_ETHER) {
-               if (ifa->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
+               if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) {
                        dn_dn2eth(mac_addr, ifa->ifa_local);
                        dev_mc_add(dev, mac_addr, ETH_ALEN, 0);
                        dev_mc_upload(dev);
@@ -561,7 +561,7 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg)
 
        switch(cmd) {
                case SIOCGIFADDR:
-                       *((dn_address *)sdn->sdn_nodeaddr) = ifa->ifa_local;
+                       *((__le16 *)sdn->sdn_nodeaddr) = ifa->ifa_local;
                        goto rarok;
 
                case SIOCSIFADDR:
@@ -804,7 +804,7 @@ done:
        return skb->len;
 }
 
-static int dn_dev_get_first(struct net_device *dev, dn_address *addr)
+static int dn_dev_get_first(struct net_device *dev, __le16 *addr)
 {
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
        struct dn_ifaddr *ifa;
@@ -830,7 +830,7 @@ out:
  * a sensible default. Eventually the routing code will take care of all the
  * nasties for us I hope.
  */
-int dn_dev_bind_default(dn_address *addr)
+int dn_dev_bind_default(__le16 *addr)
 {
        struct net_device *dev;
        int rv;
@@ -853,7 +853,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
         struct endnode_hello_message *msg;
         struct sk_buff *skb = NULL;
-        unsigned short int *pktlen;
+        __le16 *pktlen;
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
 
         if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
@@ -882,7 +882,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
         msg->datalen = 0x02;
         memset(msg->data, 0xAA, 2);
         
-        pktlen = (unsigned short *)skb_push(skb,2);
+        pktlen = (__le16 *)skb_push(skb,2);
         *pktlen = dn_htons(skb->len - 2);
 
        skb->nh.raw = skb->data;
@@ -926,7 +926,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
        size_t size;
        unsigned char *ptr;
        unsigned char *i1, *i2;
-       unsigned short *pktlen;
+       __le16 *pktlen;
        char *src;
 
        if (mtu2blksize(dev) < (26 + 7))
@@ -955,11 +955,11 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
        ptr += ETH_ALEN;
        *ptr++ = dn_db->parms.forwarding == 1 ? 
                        DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
-       *((unsigned short *)ptr) = dn_htons(mtu2blksize(dev));
+       *((__le16 *)ptr) = dn_htons(mtu2blksize(dev));
        ptr += 2;
        *ptr++ = dn_db->parms.priority; /* Priority */ 
        *ptr++ = 0; /* Area: Reserved */
-       *((unsigned short *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
+       *((__le16 *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
        ptr += 2;
        *ptr++ = 0; /* MPD: Reserved */
        i1 = ptr++;
@@ -974,7 +974,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 
        skb_trim(skb, (27 + *i2));
 
-       pktlen = (unsigned short *)skb_push(skb, 2);
+       pktlen = (__le16 *)skb_push(skb, 2);
        *pktlen = dn_htons(skb->len - 2);
 
        skb->nh.raw = skb->data;
@@ -1016,7 +1016,7 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
        ptr = skb_put(skb, 2 + 4 + tdlen);
 
        *ptr++ = DN_RT_PKT_HELO;
-       *((dn_address *)ptr) = ifa->ifa_local;
+       *((__le16 *)ptr) = ifa->ifa_local;
        ptr += 2;
        *ptr++ = tdlen;
 
@@ -1150,7 +1150,7 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
 void dn_dev_up(struct net_device *dev)
 {
        struct dn_ifaddr *ifa;
-       dn_address addr = decnet_address;
+       __le16 addr = decnet_address;
        int maybe_default = 0;
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
 
@@ -1173,7 +1173,7 @@ void dn_dev_up(struct net_device *dev)
        if (dev->type == ARPHRD_ETHER) {
                if (memcmp(dev->dev_addr, dn_hiord, 4) != 0)
                        return;
-               addr = dn_htons(dn_eth2dn(dev->dev_addr));
+               addr = dn_eth2dn(dev->dev_addr);
                maybe_default = 1;
        }
 
@@ -1385,8 +1385,8 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v)
                                mtu2blksize(dev),
                                dn_db->parms.priority,
                                dn_db->parms.state, dn_db->parms.name,
-                               dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "",
-                               dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : "");
+                               dn_db->router ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->router->primary_key), router_buf) : "",
+                               dn_db->peer ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->peer->primary_key), peer_buf) : "");
        }
        return 0;
 }
index 99bc061..bd4ce86 100644 (file)
@@ -143,11 +143,11 @@ static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi
        return NULL;
 }
 
-u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
+__le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
 {
        while(RTA_OK(attr,attrlen)) {
                if (attr->rta_type == type)
-                       return *(u16*)RTA_DATA(attr);
+                       return *(__le16*)RTA_DATA(attr);
                attr = RTA_NEXT(attr, attrlen);
        }
 
@@ -565,7 +565,7 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
        return skb->len;
 }
 
-static void fib_magic(int cmd, int type, __u16 dst, int dst_len, struct dn_ifaddr *ifa)
+static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
 {
        struct dn_fib_table *tb;
        struct {
@@ -684,7 +684,7 @@ static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event,
        return NOTIFY_DONE;
 }
 
-int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
+int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
 {
         int ret = 0;
         int scope = RT_SCOPE_NOWHERE;
index 33ab256..7c8692c 100644 (file)
@@ -95,7 +95,7 @@ static struct neigh_ops dn_phase3_ops = {
 struct neigh_table dn_neigh_table = {
        .family =                       PF_DECnet,
        .entry_size =                   sizeof(struct dn_neigh),
-       .key_len =                      sizeof(dn_address),
+       .key_len =                      sizeof(__le16),
        .hash =                         dn_neigh_hash,
        .constructor =                  dn_neigh_construct,
        .id =                           "dn_neigh_cache",
@@ -123,7 +123,7 @@ struct neigh_table dn_neigh_table = {
 
 static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev)
 {
-       return jhash_2words(*(dn_address *)pkey, 0, dn_neigh_table.hash_rnd);
+       return jhash_2words(*(__u16 *)pkey, 0, dn_neigh_table.hash_rnd);
 }
 
 static int dn_neigh_construct(struct neighbour *neigh)
@@ -249,14 +249,14 @@ static int dn_long_output(struct sk_buff *skb)
        data = skb_push(skb, sizeof(struct dn_long_packet) + 3);
        lp = (struct dn_long_packet *)(data+3);
 
-       *((unsigned short *)data) = dn_htons(skb->len - 2);
+       *((__le16 *)data) = dn_htons(skb->len - 2);
        *(data + 2) = 1 | DN_RT_F_PF; /* Padding */
 
        lp->msgflg   = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS));
        lp->d_area   = lp->d_subarea = 0;
-       dn_dn2eth(lp->d_id, dn_ntohs(cb->dst));
+       dn_dn2eth(lp->d_id, cb->dst);
        lp->s_area   = lp->s_subarea = 0;
-       dn_dn2eth(lp->s_id, dn_ntohs(cb->src));
+       dn_dn2eth(lp->s_id, cb->src);
        lp->nl2      = 0;
        lp->visit_ct = cb->hops & 0x3f;
        lp->s_class  = 0;
@@ -293,7 +293,7 @@ static int dn_short_output(struct sk_buff *skb)
         }
 
        data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
-       *((unsigned short *)data) = dn_htons(skb->len - 2);
+       *((__le16 *)data) = dn_htons(skb->len - 2);
        sp = (struct dn_short_packet *)(data+2);
 
        sp->msgflg     = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
@@ -335,7 +335,7 @@ static int dn_phase3_output(struct sk_buff *skb)
        }
 
        data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
-       *((unsigned short *)data) = dn_htons(skb->len - 2);
+       *((__le16 *)data) = dn_htons(skb->len - 2);
        sp = (struct dn_short_packet *)(data + 2);
 
        sp->msgflg   = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
@@ -373,9 +373,9 @@ int dn_neigh_router_hello(struct sk_buff *skb)
        struct neighbour *neigh;
        struct dn_neigh *dn;
        struct dn_dev *dn_db;
-       dn_address src;
+       __le16 src;
 
-       src = dn_htons(dn_eth2dn(msg->id));
+       src = dn_eth2dn(msg->id);
 
        neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
 
@@ -409,7 +409,7 @@ int dn_neigh_router_hello(struct sk_buff *skb)
                }
 
                /* Only use routers in our area */
-               if ((dn_ntohs(src)>>10) == dn_ntohs((decnet_address)>>10)) {
+               if ((dn_ntohs(src)>>10) == (dn_ntohs((decnet_address))>>10)) {
                        if (!dn_db->router) {
                                dn_db->router = neigh_clone(neigh);
                        } else {
@@ -433,9 +433,9 @@ int dn_neigh_endnode_hello(struct sk_buff *skb)
        struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data;
        struct neighbour *neigh;
        struct dn_neigh *dn;
-       dn_address src;
+       __le16 src;
 
-       src = dn_htons(dn_eth2dn(msg->id));
+       src = dn_eth2dn(msg->id);
 
        neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);
 
index 44bda85..547523b 100644 (file)
@@ -85,7 +85,7 @@ static void dn_log_martian(struct sk_buff *skb, const char *msg)
        if (decnet_log_martians && net_ratelimit()) {
                char *devname = skb->dev ? skb->dev->name : "???";
                struct dn_skb_cb *cb = DN_SKB_CB(skb);
-               printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, cb->src, cb->dst, cb->src_port, cb->dst_port);
+               printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, dn_ntohs(cb->src), dn_ntohs(cb->dst), dn_ntohs(cb->src_port), dn_ntohs(cb->dst_port));
        }
 }
 
@@ -128,7 +128,7 @@ static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack)
  */
 static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth)
 {
-       unsigned short *ptr = (unsigned short *)skb->data;
+       __le16 *ptr = (__le16 *)skb->data;
        int len = 0;
        unsigned short ack;
 
@@ -346,7 +346,7 @@ static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb)
        ptr = skb->data;
        cb->services = *ptr++;
        cb->info = *ptr++;
-       cb->segsize = dn_ntohs(*(__u16 *)ptr);
+       cb->segsize = dn_ntohs(*(__le16 *)ptr);
 
        if ((scp->state == DN_CI) || (scp->state == DN_CD)) {
                scp->persist = 0;
@@ -363,7 +363,7 @@ static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb)
                if (skb->len > 0) {
                        unsigned char dlen = *skb->data;
                        if ((dlen <= 16) && (dlen <= skb->len)) {
-                               scp->conndata_in.opt_optl = dlen;
+                               scp->conndata_in.opt_optl = dn_htons((__u16)dlen);
                                memcpy(scp->conndata_in.opt_data, skb->data + 1, dlen);
                        }
                }
@@ -397,17 +397,17 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb)
        if (skb->len < 2)
                goto out;
 
-       reason = dn_ntohs(*(__u16 *)skb->data);
+       reason = dn_ntohs(*(__le16 *)skb->data);
        skb_pull(skb, 2);
 
-       scp->discdata_in.opt_status = reason;
+       scp->discdata_in.opt_status = dn_htons(reason);
        scp->discdata_in.opt_optl   = 0;
        memset(scp->discdata_in.opt_data, 0, 16);
 
        if (skb->len > 0) {
                unsigned char dlen = *skb->data;
                if ((dlen <= 16) && (dlen <= skb->len)) {
-                       scp->discdata_in.opt_optl = dlen;
+                       scp->discdata_in.opt_optl = dn_htons((__u16)dlen);
                        memcpy(scp->discdata_in.opt_data, skb->data + 1, dlen);
                }
        }
@@ -464,7 +464,7 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb)
        if (skb->len != 2)
                goto out;
 
-       reason = dn_ntohs(*(__u16 *)skb->data);
+       reason = dn_ntohs(*(__le16 *)skb->data);
 
        sk->sk_state = TCP_CLOSE;
 
@@ -513,7 +513,7 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb)
        if (skb->len != 4)
                goto out;
 
-       segnum = dn_ntohs(*(__u16 *)ptr);
+       segnum = dn_ntohs(*(__le16 *)ptr);
        ptr += 2;
        lsflags = *(unsigned char *)ptr++;
        fcval = *ptr;
@@ -621,7 +621,7 @@ static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
        if (skb->len < 2)
                goto out;
 
-       cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data);
+       cb->segnum = segnum = dn_ntohs(*(__le16 *)skb->data);
        skb_pull(skb, 2);
 
        if (seq_next(scp->numoth_rcv, segnum)) {
@@ -649,7 +649,7 @@ static void dn_nsp_data(struct sock *sk, struct sk_buff *skb)
        if (skb->len < 2)
                goto out;
 
-       cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data);
+       cb->segnum = segnum = dn_ntohs(*(__le16 *)skb->data);
        skb_pull(skb, 2);
 
        if (seq_next(scp->numdat_rcv, segnum)) {
@@ -760,7 +760,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
        /*
         * Grab the destination address.
         */
-       cb->dst_port = *(unsigned short *)ptr;
+       cb->dst_port = *(__le16 *)ptr;
        cb->src_port = 0;
        ptr += 2;
 
@@ -768,7 +768,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
         * If not a connack, grab the source address too.
         */
        if (pskb_may_pull(skb, 5)) {
-               cb->src_port = *(unsigned short *)ptr;
+               cb->src_port = *(__le16 *)ptr;
                ptr += 2;
                skb_pull(skb, 5);
        }
@@ -778,7 +778,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
         * Swap src & dst and look up in the normal way.
         */
        if (unlikely(cb->rt_flags & DN_RT_F_RTS)) {
-               unsigned short tmp = cb->dst_port;
+               __le16 tmp = cb->dst_port;
                cb->dst_port = cb->src_port;
                cb->src_port = tmp;
                tmp = cb->dst;
index c96c767..c2e21cd 100644 (file)
@@ -287,26 +287,26 @@ int dn_nsp_xmit_timeout(struct sock *sk)
        return 0;
 }
 
-static inline unsigned char *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len)
+static inline __le16 *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len)
 {
        unsigned char *ptr = skb_push(skb, len);
 
        BUG_ON(len < 5);
 
        *ptr++ = msgflag;
-       *((unsigned short *)ptr) = scp->addrrem;
+       *((__le16 *)ptr) = scp->addrrem;
        ptr += 2;
-       *((unsigned short *)ptr) = scp->addrloc;
+       *((__le16 *)ptr) = scp->addrloc;
        ptr += 2;
-       return ptr;
+       return (__le16 __force *)ptr;
 }
 
-static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other)
+static __le16 *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other)
 {
        struct dn_scp *scp = DN_SK(sk);
        unsigned short acknum = scp->numdat_rcv & 0x0FFF;
        unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
-       unsigned short *ptr;
+       __le16 *ptr;
 
        BUG_ON(hlen < 9);
 
@@ -325,7 +325,7 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un
        /* Set "cross subchannel" bit in ackcrs */
        ackcrs |= 0x2000;
 
-       ptr = (unsigned short *)dn_mk_common_header(scp, skb, msgflag, hlen);
+       ptr = (__le16 *)dn_mk_common_header(scp, skb, msgflag, hlen);
 
        *ptr++ = dn_htons(acknum);
        *ptr++ = dn_htons(ackcrs);
@@ -333,11 +333,11 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un
        return ptr;
 }
 
-static unsigned short *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth)
+static __le16 *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth)
 {
        struct dn_scp *scp = DN_SK(sk);
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
-       unsigned short *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth);
+       __le16 *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth);
 
        if (unlikely(oth)) {
                cb->segnum = scp->numoth;
@@ -524,9 +524,9 @@ void dn_send_conn_conf(struct sock *sk, gfp_t gfp)
        struct dn_scp *scp = DN_SK(sk);
        struct sk_buff *skb = NULL;
         struct nsp_conn_init_msg *msg;
-       unsigned char len = scp->conndata_out.opt_optl;
+       __u8 len = (__u8)dn_ntohs(scp->conndata_out.opt_optl);
 
-       if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, gfp)) == NULL)
+       if ((skb = dn_alloc_skb(sk, 50 + dn_ntohs(scp->conndata_out.opt_optl), gfp)) == NULL)
                return;
 
         msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg));
@@ -553,7 +553,7 @@ void dn_send_conn_conf(struct sock *sk, gfp_t gfp)
 static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, 
                        unsigned short reason, gfp_t gfp,
                        struct dst_entry *dst,
-                       int ddl, unsigned char *dd, __u16 rem, __u16 loc)
+                       int ddl, unsigned char *dd, __le16 rem, __le16 loc)
 {
        struct sk_buff *skb = NULL;
        int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0);
@@ -561,7 +561,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
 
        if ((dst == NULL) || (rem == 0)) {
                if (net_ratelimit())
-                       printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", (unsigned)rem, dst);
+                       printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", dn_ntohs(rem), dst);
                return;
        }
 
@@ -570,11 +570,11 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
 
        msg = skb_put(skb, size);
        *msg++ = msgflg;
-       *(__u16 *)msg = rem;
+       *(__le16 *)msg = rem;
        msg += 2;
-       *(__u16 *)msg = loc;
+       *(__le16 *)msg = loc;
        msg += 2;
-       *(__u16 *)msg = dn_htons(reason);
+       *(__le16 *)msg = dn_htons(reason);
        msg += 2;
        if (msgflg == NSP_DISCINIT)
                *msg++ = ddl;
@@ -600,10 +600,10 @@ void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg,
        int ddl = 0;
 
        if (msgflg == NSP_DISCINIT)
-               ddl = scp->discdata_out.opt_optl;
+               ddl = dn_ntohs(scp->discdata_out.opt_optl);
 
        if (reason == 0)
-               reason = scp->discdata_out.opt_status;
+               reason = dn_ntohs(scp->discdata_out.opt_status);
 
        dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->sk_dst_cache, ddl, 
                scp->discdata_out.opt_data, scp->addrrem, scp->addrloc);
@@ -708,7 +708,7 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
        if (aux > 0)
        memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
 
-       aux = scp->conndata_out.opt_optl;
+       aux = (__u8)dn_ntohs(scp->conndata_out.opt_optl);
        *skb_put(skb, 1) = aux;
        if (aux > 0)
        memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux);
index 3407f19..e172cf9 100644 (file)
@@ -133,9 +133,9 @@ static struct dst_ops dn_dst_ops = {
        .entries =              ATOMIC_INIT(0),
 };
 
-static __inline__ unsigned dn_hash(unsigned short src, unsigned short dst)
+static __inline__ unsigned dn_hash(__le16 src, __le16 dst)
 {
-       unsigned short tmp = src ^ dst;
+       __u16 tmp = (__u16 __force)(src ^ dst);
        tmp ^= (tmp >> 3);
        tmp ^= (tmp >> 5);
        tmp ^= (tmp >> 10);
@@ -149,8 +149,7 @@ static inline void dnrt_free(struct dn_route *rt)
 
 static inline void dnrt_drop(struct dn_route *rt)
 {
-       if (rt)
-               dst_release(&rt->u.dst);
+       dst_release(&rt->u.dst);
        call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
 }
 
@@ -379,9 +378,9 @@ static int dn_return_short(struct sk_buff *skb)
 {
        struct dn_skb_cb *cb;
        unsigned char *ptr;
-       dn_address *src;
-       dn_address *dst;
-       dn_address tmp;
+       __le16 *src;
+       __le16 *dst;
+       __le16 tmp;
 
        /* Add back headers */
        skb_push(skb, skb->data - skb->nh.raw);
@@ -394,9 +393,9 @@ static int dn_return_short(struct sk_buff *skb)
        ptr = skb->data + 2;
        *ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS;
 
-       dst = (dn_address *)ptr;
+       dst = (__le16 *)ptr;
        ptr += 2;
-       src = (dn_address *)ptr;
+       src = (__le16 *)ptr;
        ptr += 2;
        *ptr = 0; /* Zero hop count */
 
@@ -475,7 +474,8 @@ static int dn_route_rx_packet(struct sk_buff *skb)
                struct dn_skb_cb *cb = DN_SKB_CB(skb);
                printk(KERN_DEBUG
                        "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n",
-                       (int)cb->rt_flags, devname, skb->len, cb->src, cb->dst, 
+                       (int)cb->rt_flags, devname, skb->len,
+                       dn_ntohs(cb->src), dn_ntohs(cb->dst),
                        err, skb->pkt_type);
        }
 
@@ -505,7 +505,7 @@ static int dn_route_rx_long(struct sk_buff *skb)
 
         /* Destination info */
         ptr += 2;
-       cb->dst = dn_htons(dn_eth2dn(ptr));
+       cb->dst = dn_eth2dn(ptr);
         if (memcmp(ptr, dn_hiord_addr, 4) != 0)
                 goto drop_it;
         ptr += 6;
@@ -513,7 +513,7 @@ static int dn_route_rx_long(struct sk_buff *skb)
 
         /* Source info */
         ptr += 2;
-       cb->src = dn_htons(dn_eth2dn(ptr));
+       cb->src = dn_eth2dn(ptr);
         if (memcmp(ptr, dn_hiord_addr, 4) != 0)
                 goto drop_it;
         ptr += 6;
@@ -541,9 +541,9 @@ static int dn_route_rx_short(struct sk_buff *skb)
        skb_pull(skb, 5);
        skb->h.raw = skb->data;
 
-       cb->dst = *(dn_address *)ptr;
+       cb->dst = *(__le16 *)ptr;
         ptr += 2;
-        cb->src = *(dn_address *)ptr;
+        cb->src = *(__le16 *)ptr;
         ptr += 2;
         cb->hops = *ptr & 0x3f;
 
@@ -575,7 +575,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
 {
        struct dn_skb_cb *cb;
        unsigned char flags = 0;
-       __u16 len = dn_ntohs(*(__u16 *)skb->data);
+       __u16 len = dn_ntohs(*(__le16 *)skb->data);
        struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr;
        unsigned char padlen = 0;
 
@@ -782,7 +782,7 @@ static int dn_rt_bug(struct sk_buff *skb)
                struct dn_skb_cb *cb = DN_SKB_CB(skb);
 
                printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n",
-                               cb->src, cb->dst);
+                               dn_ntohs(cb->src), dn_ntohs(cb->dst));
        }
 
        kfree_skb(skb);
@@ -823,7 +823,7 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
        return 0;
 }
 
-static inline int dn_match_addr(__u16 addr1, __u16 addr2)
+static inline int dn_match_addr(__le16 addr1, __le16 addr2)
 {
        __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
        int match = 16;
@@ -834,9 +834,9 @@ static inline int dn_match_addr(__u16 addr1, __u16 addr2)
        return match;
 }
 
-static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int scope)
+static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope)
 {
-       __u16 saddr = 0;
+       __le16 saddr = 0;
        struct dn_dev *dn_db = dev->dn_ptr;
        struct dn_ifaddr *ifa;
        int best_match = 0;
@@ -861,14 +861,14 @@ static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int s
        return saddr;
 }
 
-static inline __u16 __dn_fib_res_prefsrc(struct dn_fib_res *res)
+static inline __le16 __dn_fib_res_prefsrc(struct dn_fib_res *res)
 {
        return dnet_select_source(DN_FIB_RES_DEV(*res), DN_FIB_RES_GW(*res), res->scope);
 }
 
-static inline __u16 dn_fib_rules_map_destination(__u16 daddr, struct dn_fib_res *res)
+static inline __le16 dn_fib_rules_map_destination(__le16 daddr, struct dn_fib_res *res)
 {
-       __u16 mask = dnet_make_mask(res->prefixlen);
+       __le16 mask = dnet_make_mask(res->prefixlen);
        return (daddr&~mask)|res->fi->fib_nh->nh_gw;
 }
 
@@ -892,12 +892,13 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
        struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST };
        int err;
        int free_res = 0;
-       __u16 gateway = 0;
+       __le16 gateway = 0;
 
        if (decnet_debug_level & 16)
                printk(KERN_DEBUG
                       "dn_route_output_slow: dst=%04x src=%04x mark=%d"
-                      " iif=%d oif=%d\n", oldflp->fld_dst, oldflp->fld_src,
+                      " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst),
+                      dn_ntohs(oldflp->fld_src),
                        oldflp->fld_fwmark, loopback_dev.ifindex, oldflp->oif);
 
        /* If we have an output interface, verify its a DECnet device */
@@ -961,8 +962,9 @@ source_ok:
        if (decnet_debug_level & 16)
                printk(KERN_DEBUG
                       "dn_route_output_slow: initial checks complete."
-                      " dst=%o4x src=%04x oif=%d try_hard=%d\n", fl.fld_dst,
-                      fl.fld_src, fl.oif, try_hard);
+                      " dst=%o4x src=%04x oif=%d try_hard=%d\n",
+                      dn_ntohs(fl.fld_dst), dn_ntohs(fl.fld_src),
+                      fl.oif, try_hard);
 
        /*
         * N.B. If the kernel is compiled without router support then
@@ -1218,8 +1220,8 @@ static int dn_route_input_slow(struct sk_buff *skb)
        struct neighbour *neigh = NULL;
        unsigned hash;
        int flags = 0;
-       __u16 gateway = 0;
-       __u16 local_src = 0;
+       __le16 gateway = 0;
+       __le16 local_src = 0;
        struct flowi fl = { .nl_u = { .dn_u = 
                                     { .daddr = cb->dst,
                                       .saddr = cb->src,
@@ -1266,7 +1268,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
                res.type = RTN_LOCAL;
                flags |= RTCF_DIRECTSRC;
        } else {
-               __u16 src_map = fl.fld_src;
+               __le16 src_map = fl.fld_src;
                free_res = 1;
 
                out_dev = DN_FIB_RES_DEV(res);
index 1060de7..446faaf 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/timer.h>
 #include <linux/spinlock.h>
 #include <linux/in_route.h>
+#include <linux/list.h>
+#include <linux/rcupdate.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
 #include <net/neighbour.h>
 
 struct dn_fib_rule
 {
-       struct dn_fib_rule      *r_next;
+       struct hlist_node       r_hlist;
        atomic_t                r_clntref;
        u32                     r_preference;
        unsigned char           r_table;
        unsigned char           r_action;
        unsigned char           r_dst_len;
        unsigned char           r_src_len;
-       dn_address              r_src;
-       dn_address              r_srcmask;
-       dn_address              r_dst;
-       dn_address              r_dstmask;
-       dn_address              r_srcmap;
+       __le16                  r_src;
+       __le16                  r_srcmask;
+       __le16                  r_dst;
+       __le16                  r_dstmask;
+       __le16                  r_srcmap;
        u8                      r_flags;
 #ifdef CONFIG_DECNET_ROUTE_FWMARK
        u32                     r_fwmark;
@@ -58,6 +60,7 @@ struct dn_fib_rule
        int                     r_ifindex;
        char                    r_ifname[IFNAMSIZ];
        int                     r_dead;
+       struct rcu_head         rcu;
 };
 
 static struct dn_fib_rule default_rule = {
@@ -67,18 +70,17 @@ static struct dn_fib_rule default_rule = {
        .r_action =             RTN_UNICAST
 };
 
-static struct dn_fib_rule *dn_fib_rules = &default_rule;
-static DEFINE_RWLOCK(dn_fib_rules_lock);
-
+static struct hlist_head dn_fib_rules;
 
 int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct rtattr **rta = arg;
        struct rtmsg *rtm = NLMSG_DATA(nlh);
-       struct dn_fib_rule *r, **rp;
+       struct dn_fib_rule *r;
+       struct hlist_node *node;
        int err = -ESRCH;
 
-       for(rp=&dn_fib_rules; (r=*rp) != NULL; rp = &r->r_next) {
+       hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
                if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) &&
                        rtm->rtm_src_len == r->r_src_len &&
                        rtm->rtm_dst_len == r->r_dst_len &&
@@ -95,10 +97,8 @@ int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                        if (r == &default_rule)
                                break;
 
-                       write_lock_bh(&dn_fib_rules_lock);
-                       *rp = r->r_next;
+                       hlist_del_rcu(&r->r_hlist);
                        r->r_dead = 1;
-                       write_unlock_bh(&dn_fib_rules_lock);
                        dn_fib_rule_put(r);
                        err = 0;
                        break;
@@ -108,11 +108,17 @@ int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        return err;
 }
 
+static inline void dn_fib_rule_put_rcu(struct rcu_head *head)
+{
+       struct dn_fib_rule *r = container_of(head, struct dn_fib_rule, rcu);
+       kfree(r);
+}
+
 void dn_fib_rule_put(struct dn_fib_rule *r)
 {
        if (atomic_dec_and_test(&r->r_clntref)) {
                if (r->r_dead)
-                       kfree(r);
+                       call_rcu(&r->rcu, dn_fib_rule_put_rcu);
                else
                        printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n");
        }
@@ -123,7 +129,8 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct rtattr **rta = arg;
        struct rtmsg *rtm = NLMSG_DATA(nlh);
-       struct dn_fib_rule *r, *new_r, **rp;
+       struct dn_fib_rule *r, *new_r, *last = NULL;
+       struct hlist_node *node = NULL;
        unsigned char table_id;
 
        if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16)
@@ -149,6 +156,7 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        if (!new_r)
                return -ENOMEM;
        memset(new_r, 0, sizeof(*new_r));
+
        if (rta[RTA_SRC-1])
                memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2);
        if (rta[RTA_DST-1])
@@ -179,27 +187,26 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                }
        }
 
-       rp = &dn_fib_rules;
+       r = container_of(dn_fib_rules.first, struct dn_fib_rule, r_hlist);
        if (!new_r->r_preference) {
-               r = dn_fib_rules;
-               if (r && (r = r->r_next) != NULL) {
-                       rp = &dn_fib_rules->r_next;
+               if (r && r->r_hlist.next != NULL) {
+                       r = container_of(r->r_hlist.next, struct dn_fib_rule, r_hlist);
                        if (r->r_preference)
                                new_r->r_preference = r->r_preference - 1;
                }
        }
 
-       while((r=*rp) != NULL) {
+       hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
                if (r->r_preference > new_r->r_preference)
                        break;
-               rp = &r->r_next;
+               last = r;
        }
-
-       new_r->r_next = r;
        atomic_inc(&new_r->r_clntref);
-       write_lock_bh(&dn_fib_rules_lock);
-       *rp = new_r;
-       write_unlock_bh(&dn_fib_rules_lock);
+
+       if (last)
+               hlist_add_after_rcu(&last->r_hlist, &new_r->r_hlist);
+       else
+               hlist_add_before_rcu(&new_r->r_hlist, &r->r_hlist);
        return 0;
 }
 
@@ -208,12 +215,14 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
 {
        struct dn_fib_rule *r, *policy;
        struct dn_fib_table *tb;
-       dn_address saddr = flp->fld_src;
-       dn_address daddr = flp->fld_dst;
+       __le16 saddr = flp->fld_src;
+       __le16 daddr = flp->fld_dst;
+       struct hlist_node *node;
        int err;
 
-       read_lock(&dn_fib_rules_lock);
-       for(r = dn_fib_rules; r; r = r->r_next) {
+       rcu_read_lock();
+
+       hlist_for_each_entry_rcu(r, node, &dn_fib_rules, r_hlist) {
                if (((saddr^r->r_src) & r->r_srcmask) ||
                    ((daddr^r->r_dst) & r->r_dstmask) ||
 #ifdef CONFIG_DECNET_ROUTE_FWMARK
@@ -228,14 +237,14 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
                                policy = r;
                                break;
                        case RTN_UNREACHABLE:
-                               read_unlock(&dn_fib_rules_lock);
+                               rcu_read_unlock();
                                return -ENETUNREACH;
                        default:
                        case RTN_BLACKHOLE:
-                               read_unlock(&dn_fib_rules_lock);
+                               rcu_read_unlock();
                                return -EINVAL;
                        case RTN_PROHIBIT:
-                               read_unlock(&dn_fib_rules_lock);
+                               rcu_read_unlock();
                                return -EACCES;
                }
 
@@ -246,20 +255,20 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
                        res->r = policy;
                        if (policy)
                                atomic_inc(&policy->r_clntref);
-                       read_unlock(&dn_fib_rules_lock);
+                       rcu_read_unlock();
                        return 0;
                }
                if (err < 0 && err != -EAGAIN) {
-                       read_unlock(&dn_fib_rules_lock);
+                       rcu_read_unlock();
                        return err;
                }
        }
 
-       read_unlock(&dn_fib_rules_lock);
+       rcu_read_unlock();
        return -ESRCH;
 }
 
-unsigned dnet_addr_type(__u16 addr)
+unsigned dnet_addr_type(__le16 addr)
 {
        struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } };
        struct dn_fib_res res;
@@ -277,7 +286,7 @@ unsigned dnet_addr_type(__u16 addr)
        return ret;
 }
 
-__u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags)
+__le16 dn_fib_rules_policy(__le16 saddr, struct dn_fib_res *res, unsigned *flags)
 {
        struct dn_fib_rule *r = res->r;
 
@@ -297,27 +306,23 @@ __u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags)
 
 static void dn_fib_rules_detach(struct net_device *dev)
 {
+       struct hlist_node *node;
        struct dn_fib_rule *r;
 
-       for(r = dn_fib_rules; r; r = r->r_next) {
-               if (r->r_ifindex == dev->ifindex) {
-                       write_lock_bh(&dn_fib_rules_lock);
+       hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
+               if (r->r_ifindex == dev->ifindex)
                        r->r_ifindex = -1;
-                       write_unlock_bh(&dn_fib_rules_lock);
-               }
        }
 }
 
 static void dn_fib_rules_attach(struct net_device *dev)
 {
+       struct hlist_node *node;
        struct dn_fib_rule *r;
 
-       for(r = dn_fib_rules; r; r = r->r_next) {
-               if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
-                       write_lock_bh(&dn_fib_rules_lock);
+       hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
+               if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
                        r->r_ifindex = dev->ifindex;
-                       write_unlock_bh(&dn_fib_rules_lock);
-               }
        }
 }
 
@@ -387,18 +392,20 @@ rtattr_failure:
 
 int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       int idx;
+       int idx = 0;
        int s_idx = cb->args[0];
        struct dn_fib_rule *r;
+       struct hlist_node *node;
 
-       read_lock(&dn_fib_rules_lock);
-       for(r = dn_fib_rules, idx = 0; r; r = r->r_next, idx++) {
+       rcu_read_lock();
+       hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
                if (idx < s_idx)
                        continue;
                if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0)
                        break;
+               idx++;
        }
-       read_unlock(&dn_fib_rules_lock);
+       rcu_read_unlock();
        cb->args[0] = idx;
 
        return skb->len;
@@ -406,6 +413,8 @@ int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
 
 void __init dn_fib_rules_init(void)
 {
+       INIT_HLIST_HEAD(&dn_fib_rules);
+       hlist_add_head(&default_rule.r_hlist, &dn_fib_rules);
        register_netdevice_notifier(&dn_fib_rules_notifier);
 }
 
index 6f8b565..0ebc46a 100644 (file)
@@ -46,7 +46,7 @@ struct dn_zone
        u32                     dz_hashmask;
 #define DZ_HASHMASK(dz)        ((dz)->dz_hashmask)
        int                     dz_order;
-       u16                     dz_mask;
+       __le16                  dz_mask;
 #define DZ_MASK(dz)    ((dz)->dz_mask)
 };
 
@@ -84,14 +84,14 @@ static int dn_fib_hash_zombies;
 
 static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
 {
-       u16 h = ntohs(key.datum)>>(16 - dz->dz_order);
+       u16 h = dn_ntohs(key.datum)>>(16 - dz->dz_order);
        h ^= (h >> 10);
        h ^= (h >> 6);
        h &= DZ_HASHMASK(dz);
        return *(dn_fib_idx_t *)&h;
 }
 
-static inline dn_fib_key_t dz_key(u16 dst, struct dn_zone *dz)
+static inline dn_fib_key_t dz_key(__le16 dst, struct dn_zone *dz)
 {
        dn_fib_key_t k;
        k.datum = dst & DZ_MASK(dz);
@@ -250,7 +250,7 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern
 
        for_nexthops(fi) {
                int attrlen = nhlen - sizeof(struct rtnexthop);
-               dn_address gw;
+               __le16 gw;
 
                if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
                        return -EINVAL;
@@ -457,7 +457,7 @@ static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct
 
        dz_key_0(key);
        if (rta->rta_dst) {
-               dn_address dst;
+               __le16 dst;
                memcpy(&dst, rta->rta_dst, 2);
                if (dst & ~DZ_MASK(dz))
                        return -EINVAL;
@@ -593,7 +593,7 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct
 
        dz_key_0(key);
        if (rta->rta_dst) {
-               dn_address dst;
+               __le16 dst;
                memcpy(&dst, rta->rta_dst, 2);
                if (dst & ~DZ_MASK(dz))
                        return -EINVAL;
index 0e9d2c5..bda5920 100644 (file)
@@ -86,9 +86,9 @@ static void strip_it(char *str)
  * Simple routine to parse an ascii DECnet address
  * into a network order address.
  */
-static int parse_addr(dn_address *addr, char *str)
+static int parse_addr(__le16 *addr, char *str)
 {
-       dn_address area, node;
+       __u16 area, node;
 
        while(*str && !ISNUM(*str)) str++;
 
@@ -139,7 +139,7 @@ static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen
                                void **context)
 {
        size_t len;
-       dn_address addr;
+       __le16 addr;
 
        if (oldval && oldlenp) {
                if (get_user(len, oldlenp))
@@ -147,14 +147,14 @@ static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen
                if (len) {
                        if (len != sizeof(unsigned short))
                                return -EINVAL;
-                       if (put_user(decnet_address, (unsigned short __user *)oldval))
+                       if (put_user(decnet_address, (__le16 __user *)oldval))
                                return -EFAULT;
                }
        }
        if (newval && newlen) {
                if (newlen != sizeof(unsigned short))
                        return -EINVAL;
-               if (get_user(addr, (unsigned short __user *)newval))
+               if (get_user(addr, (__le16 __user *)newval))
                        return -EFAULT;
 
                dn_dev_devices_off();
@@ -173,7 +173,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
 {
        char addr[DN_ASCBUF_LEN];
        size_t len;
-       dn_address dnaddr;
+       __le16 dnaddr;
 
        if (!*lenp || (*ppos && !write)) {
                *lenp = 0;
index 97c276f..dc206f1 100644 (file)
@@ -788,45 +788,53 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 }
 
 const struct proto_ops inet_stream_ops = {
-       .family =       PF_INET,
-       .owner =        THIS_MODULE,
-       .release =      inet_release,
-       .bind =         inet_bind,
-       .connect =      inet_stream_connect,
-       .socketpair =   sock_no_socketpair,
-       .accept =       inet_accept,
-       .getname =      inet_getname,
-       .poll =         tcp_poll,
-       .ioctl =        inet_ioctl,
-       .listen =       inet_listen,
-       .shutdown =     inet_shutdown,
-       .setsockopt =   sock_common_setsockopt,
-       .getsockopt =   sock_common_getsockopt,
-       .sendmsg =      inet_sendmsg,
-       .recvmsg =      sock_common_recvmsg,
-       .mmap =         sock_no_mmap,
-       .sendpage =     tcp_sendpage
+       .family            = PF_INET,
+       .owner             = THIS_MODULE,
+       .release           = inet_release,
+       .bind              = inet_bind,
+       .connect           = inet_stream_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = inet_accept,
+       .getname           = inet_getname,
+       .poll              = tcp_poll,
+       .ioctl             = inet_ioctl,
+       .listen            = inet_listen,
+       .shutdown          = inet_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = tcp_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 const struct proto_ops inet_dgram_ops = {
-       .family =       PF_INET,
-       .owner =        THIS_MODULE,
-       .release =      inet_release,
-       .bind =         inet_bind,
-       .connect =      inet_dgram_connect,
-       .socketpair =   sock_no_socketpair,
-       .accept =       sock_no_accept,
-       .getname =      inet_getname,
-       .poll =         udp_poll,
-       .ioctl =        inet_ioctl,
-       .listen =       sock_no_listen,
-       .shutdown =     inet_shutdown,
-       .setsockopt =   sock_common_setsockopt,
-       .getsockopt =   sock_common_getsockopt,
-       .sendmsg =      inet_sendmsg,
-       .recvmsg =      sock_common_recvmsg,
-       .mmap =         sock_no_mmap,
-       .sendpage =     inet_sendpage,
+       .family            = PF_INET,
+       .owner             = THIS_MODULE,
+       .release           = inet_release,
+       .bind              = inet_bind,
+       .connect           = inet_dgram_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = sock_no_accept,
+       .getname           = inet_getname,
+       .poll              = udp_poll,
+       .ioctl             = inet_ioctl,
+       .listen            = sock_no_listen,
+       .shutdown          = inet_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = inet_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 /*
@@ -834,24 +842,28 @@ const struct proto_ops inet_dgram_ops = {
  * udp_poll
  */
 static const struct proto_ops inet_sockraw_ops = {
-       .family =       PF_INET,
-       .owner =        THIS_MODULE,
-       .release =      inet_release,
-       .bind =         inet_bind,
-       .connect =      inet_dgram_connect,
-       .socketpair =   sock_no_socketpair,
-       .accept =       sock_no_accept,
-       .getname =      inet_getname,
-       .poll =         datagram_poll,
-       .ioctl =        inet_ioctl,
-       .listen =       sock_no_listen,
-       .shutdown =     inet_shutdown,
-       .setsockopt =   sock_common_setsockopt,
-       .getsockopt =   sock_common_getsockopt,
-       .sendmsg =      inet_sendmsg,
-       .recvmsg =      sock_common_recvmsg,
-       .mmap =         sock_no_mmap,
-       .sendpage =     inet_sendpage,
+       .family            = PF_INET,
+       .owner             = THIS_MODULE,
+       .release           = inet_release,
+       .bind              = inet_bind,
+       .connect           = inet_dgram_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = sock_no_accept,
+       .getname           = inet_getname,
+       .poll              = datagram_poll,
+       .ioctl             = inet_ioctl,
+       .listen            = sock_no_listen,
+       .shutdown          = inet_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = inet_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 static struct net_proto_family inet_family_ops = {
index aed537f..e16d8b4 100644 (file)
@@ -97,6 +97,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
        ah->reserved = 0;
        ah->spi = x->id.spi;
        ah->seq_no = htonl(++x->replay.oseq);
+       xfrm_aevent_doreplay(x);
        ahp->icv(ahp, skb, ah->auth_data);
 
        top_iph->tos = iph->tos;
index accdefe..041dadd 100644 (file)
@@ -879,16 +879,16 @@ static int arp_process(struct sk_buff *skb)
 
        n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
 
-#ifdef CONFIG_IP_ACCEPT_UNSOLICITED_ARP
-       /* Unsolicited ARP is not accepted by default.
-          It is possible, that this option should be enabled for some
-          devices (strip is candidate)
-        */
-       if (n == NULL &&
-           arp->ar_op == htons(ARPOP_REPLY) &&
-           inet_addr_type(sip) == RTN_UNICAST)
-               n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
-#endif
+       if (ipv4_devconf.arp_accept) {
+               /* Unsolicited ARP is not accepted by default.
+                  It is possible, that this option should be enabled for some
+                  devices (strip is candidate)
+                */
+               if (n == NULL &&
+                   arp->ar_op == htons(ARPOP_REPLY) &&
+                   inet_addr_type(sip) == RTN_UNICAST)
+                       n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
+       }
 
        if (n) {
                int state = NUD_REACHABLE;
index 3ffa60d..44fdf14 100644 (file)
@@ -1394,6 +1394,14 @@ static struct devinet_sysctl_table {
                        .proc_handler   = &proc_dointvec,
                },
                {
+                       .ctl_name       = NET_IPV4_CONF_ARP_ACCEPT,
+                       .procname       = "arp_accept",
+                       .data           = &ipv4_devconf.arp_accept,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = &proc_dointvec,
+               },
+               {
                        .ctl_name       = NET_IPV4_CONF_NOXFRM,
                        .procname       = "disable_xfrm",
                        .data           = &ipv4_devconf.no_xfrm,
index 09590f3..bf88c62 100644 (file)
@@ -90,6 +90,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
 
        esph->spi = x->id.spi;
        esph->seq_no = htonl(++x->replay.oseq);
+       xfrm_aevent_doreplay(x);
 
        if (esp->conf.ivlen)
                crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
index 0dd4d06..768e8f5 100644 (file)
@@ -40,6 +40,8 @@
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/init.h>
+#include <linux/list.h>
+#include <linux/rcupdate.h>
 
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -52,7 +54,7 @@
 
 struct fib_rule
 {
-       struct fib_rule *r_next;
+       struct hlist_node hlist;
        atomic_t        r_clntref;
        u32             r_preference;
        unsigned char   r_table;
@@ -75,6 +77,7 @@ struct fib_rule
 #endif
        char            r_ifname[IFNAMSIZ];
        int             r_dead;
+       struct          rcu_head rcu;
 };
 
 static struct fib_rule default_rule = {
@@ -85,7 +88,6 @@ static struct fib_rule default_rule = {
 };
 
 static struct fib_rule main_rule = {
-       .r_next =       &default_rule,
        .r_clntref =    ATOMIC_INIT(2),
        .r_preference = 0x7FFE,
        .r_table =      RT_TABLE_MAIN,
@@ -93,23 +95,24 @@ static struct fib_rule main_rule = {
 };
 
 static struct fib_rule local_rule = {
-       .r_next =       &main_rule,
        .r_clntref =    ATOMIC_INIT(2),
        .r_table =      RT_TABLE_LOCAL,
        .r_action =     RTN_UNICAST,
 };
 
-static struct fib_rule *fib_rules = &local_rule;
-static DEFINE_RWLOCK(fib_rules_lock);
+static struct hlist_head fib_rules;
+
+/* writer func called from netlink -- rtnl_sem hold*/
 
 int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
        struct rtattr **rta = arg;
        struct rtmsg *rtm = NLMSG_DATA(nlh);
-       struct fib_rule *r, **rp;
+       struct fib_rule *r;
+       struct hlist_node *node;
        int err = -ESRCH;
 
-       for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) {
+       hlist_for_each_entry(r, node, &fib_rules, hlist) {
                if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
                    rtm->rtm_src_len == r->r_src_len &&
                    rtm->rtm_dst_len == r->r_dst_len &&
@@ -126,10 +129,8 @@ int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
                        if (r == &local_rule)
                                break;
 
-                       write_lock_bh(&fib_rules_lock);
-                       *rp = r->r_next;
+                       hlist_del_rcu(&r->hlist);
                        r->r_dead = 1;
-                       write_unlock_bh(&fib_rules_lock);
                        fib_rule_put(r);
                        err = 0;
                        break;
@@ -150,21 +151,30 @@ static struct fib_table *fib_empty_table(void)
        return NULL;
 }
 
+static inline void fib_rule_put_rcu(struct rcu_head *head)
+{
+       struct fib_rule *r = container_of(head, struct fib_rule, rcu);
+       kfree(r);
+}
+
 void fib_rule_put(struct fib_rule *r)
 {
        if (atomic_dec_and_test(&r->r_clntref)) {
                if (r->r_dead)
-                       kfree(r);
+                       call_rcu(&r->rcu, fib_rule_put_rcu);
                else
                        printk("Freeing alive rule %p\n", r);
        }
 }
 
+/* writer func called from netlink -- rtnl_sem hold*/
+
 int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
        struct rtattr **rta = arg;
        struct rtmsg *rtm = NLMSG_DATA(nlh);
-       struct fib_rule *r, *new_r, **rp;
+       struct fib_rule *r, *new_r, *last = NULL;
+       struct hlist_node *node = NULL;
        unsigned char table_id;
 
        if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 ||
@@ -188,6 +198,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
        if (!new_r)
                return -ENOMEM;
        memset(new_r, 0, sizeof(*new_r));
+
        if (rta[RTA_SRC-1])
                memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4);
        if (rta[RTA_DST-1])
@@ -220,28 +231,28 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
        if (rta[RTA_FLOW-1])
                memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
 #endif
+       r = container_of(fib_rules.first, struct fib_rule, hlist);
 
-       rp = &fib_rules;
        if (!new_r->r_preference) {
-               r = fib_rules;
-               if (r && (r = r->r_next) != NULL) {
-                       rp = &fib_rules->r_next;
+               if (r && r->hlist.next != NULL) {
+                       r = container_of(r->hlist.next, struct fib_rule, hlist);
                        if (r->r_preference)
                                new_r->r_preference = r->r_preference - 1;
                }
        }
 
-       while ( (r = *rp) != NULL ) {
+       hlist_for_each_entry(r, node, &fib_rules, hlist) {
                if (r->r_preference > new_r->r_preference)
                        break;
-               rp = &r->r_next;
+               last = r;
        }
-
-       new_r->r_next = r;
        atomic_inc(&new_r->r_clntref);
-       write_lock_bh(&fib_rules_lock);
-       *rp = new_r;
-       write_unlock_bh(&fib_rules_lock);
+
+       if (last)
+               hlist_add_after_rcu(&last->hlist, &new_r->hlist);
+       else
+               hlist_add_before_rcu(&new_r->hlist, &r->hlist);
+
        return 0;
 }
 
@@ -254,30 +265,30 @@ u32 fib_rules_tclass(struct fib_result *res)
 }
 #endif
 
+/* callers should hold rtnl semaphore */
 
 static void fib_rules_detach(struct net_device *dev)
 {
+       struct hlist_node *node;
        struct fib_rule *r;
 
-       for (r=fib_rules; r; r=r->r_next) {
-               if (r->r_ifindex == dev->ifindex) {
-                       write_lock_bh(&fib_rules_lock);
+       hlist_for_each_entry(r, node, &fib_rules, hlist) {
+               if (r->r_ifindex == dev->ifindex)
                        r->r_ifindex = -1;
-                       write_unlock_bh(&fib_rules_lock);
-               }
+
        }
 }
 
+/* callers should hold rtnl semaphore */
+
 static void fib_rules_attach(struct net_device *dev)
 {
+       struct hlist_node *node;
        struct fib_rule *r;
 
-       for (r=fib_rules; r; r=r->r_next) {
-               if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
-                       write_lock_bh(&fib_rules_lock);
+       hlist_for_each_entry(r, node, &fib_rules, hlist) {
+               if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
                        r->r_ifindex = dev->ifindex;
-                       write_unlock_bh(&fib_rules_lock);
-               }
        }
 }
 
@@ -286,14 +297,17 @@ int fib_lookup(const struct flowi *flp, struct fib_result *res)
        int err;
        struct fib_rule *r, *policy;
        struct fib_table *tb;
+       struct hlist_node *node;
 
        u32 daddr = flp->fl4_dst;
        u32 saddr = flp->fl4_src;
 
 FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
        NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src));
-       read_lock(&fib_rules_lock);
-       for (r = fib_rules; r; r=r->r_next) {
+
+       rcu_read_lock();
+
+       hlist_for_each_entry_rcu(r, node, &fib_rules, hlist) {
                if (((saddr^r->r_src) & r->r_srcmask) ||
                    ((daddr^r->r_dst) & r->r_dstmask) ||
                    (r->r_tos && r->r_tos != flp->fl4_tos) ||
@@ -309,14 +323,14 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
                        policy = r;
                        break;
                case RTN_UNREACHABLE:
-                       read_unlock(&fib_rules_lock);
+                       rcu_read_unlock();
                        return -ENETUNREACH;
                default:
                case RTN_BLACKHOLE:
-                       read_unlock(&fib_rules_lock);
+                       rcu_read_unlock();
                        return -EINVAL;
                case RTN_PROHIBIT:
-                       read_unlock(&fib_rules_lock);
+                       rcu_read_unlock();
                        return -EACCES;
                }
 
@@ -327,16 +341,16 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
                        res->r = policy;
                        if (policy)
                                atomic_inc(&policy->r_clntref);
-                       read_unlock(&fib_rules_lock);
+                       rcu_read_unlock();
                        return 0;
                }
                if (err < 0 && err != -EAGAIN) {
-                       read_unlock(&fib_rules_lock);
+                       rcu_read_unlock();
                        return err;
                }
        }
 FRprintk("FAILURE\n");
-       read_unlock(&fib_rules_lock);
+       rcu_read_unlock();
        return -ENETUNREACH;
 }
 
@@ -414,20 +428,25 @@ rtattr_failure:
        return -1;
 }
 
+/* callers should hold rtnl semaphore */
+
 int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       int idx;
+       int idx = 0;
        int s_idx = cb->args[0];
        struct fib_rule *r;
+       struct hlist_node *node;
+
+       rcu_read_lock();
+       hlist_for_each_entry(r, node, &fib_rules, hlist) {
 
-       read_lock(&fib_rules_lock);
-       for (r=fib_rules, idx=0; r; r = r->r_next, idx++) {
                if (idx < s_idx)
                        continue;
                if (inet_fill_rule(skb, r, cb, NLM_F_MULTI) < 0)
                        break;
+               idx++;
        }
-       read_unlock(&fib_rules_lock);
+       rcu_read_unlock();
        cb->args[0] = idx;
 
        return skb->len;
@@ -435,5 +454,9 @@ int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
 
 void __init fib_rules_init(void)
 {
+       INIT_HLIST_HEAD(&fib_rules);
+       hlist_add_head(&local_rule.hlist, &fib_rules);
+       hlist_add_after(&local_rule.hlist, &main_rule.hlist);
+       hlist_add_after(&main_rule.hlist, &default_rule.hlist);
        register_netdevice_notifier(&fib_rules_notifier);
 }
index e320b32..ccd3efc 100644 (file)
@@ -50,7 +50,7 @@
  *             Patrick McHardy <kaber@trash.net>
  */
 
-#define VERSION "0.404"
+#define VERSION "0.406"
 
 #include <linux/config.h>
 #include <asm/uaccess.h>
@@ -84,7 +84,7 @@
 #include "fib_lookup.h"
 
 #undef CONFIG_IP_FIB_TRIE_STATS
-#define MAX_CHILDS 16384
+#define MAX_STAT_DEPTH 32
 
 #define KEYLENGTH (8*sizeof(t_key))
 #define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l))
@@ -154,7 +154,7 @@ struct trie_stat {
        unsigned int tnodes;
        unsigned int leaves;
        unsigned int nullpointers;
-       unsigned int nodesizes[MAX_CHILDS];
+       unsigned int nodesizes[MAX_STAT_DEPTH];
 };
 
 struct trie {
@@ -2040,7 +2040,15 @@ rescan:
 static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
                                       struct trie *t)
 {
-       struct node *n = rcu_dereference(t->trie);
+       struct node *n ;
+
+       if(!t)
+               return NULL;
+
+       n = rcu_dereference(t->trie);
+
+       if(!iter)
+               return NULL;
 
        if (n && IS_TNODE(n)) {
                iter->tnode = (struct tnode *) n;
@@ -2072,7 +2080,9 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
                        int i;
 
                        s->tnodes++;
-                       s->nodesizes[tn->bits]++;
+                       if(tn->bits < MAX_STAT_DEPTH)
+                               s->nodesizes[tn->bits]++;
+
                        for (i = 0; i < (1<<tn->bits); i++)
                                if (!tn->child[i])
                                        s->nullpointers++;
@@ -2102,8 +2112,8 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
        seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes);
        bytes += sizeof(struct tnode) * stat->tnodes;
 
-       max = MAX_CHILDS-1;
-       while (max >= 0 && stat->nodesizes[max] == 0)
+       max = MAX_STAT_DEPTH;
+       while (max > 0 && stat->nodesizes[max-1] == 0)
                max--;
 
        pointers = 0;
index 64ce52b..d512239 100644 (file)
@@ -1382,7 +1382,7 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
                dev = ip_dev_find(imr->imr_address.s_addr);
                if (!dev)
                        return NULL;
-               __dev_put(dev);
+               dev_put(dev);
        }
 
        if (!dev && !ip_route_output_key(&rt, &fl)) {
@@ -1730,7 +1730,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
        if (!MULTICAST(addr))
                return -EINVAL;
 
-       rtnl_shlock();
+       rtnl_lock();
 
        in_dev = ip_mc_find_dev(imr);
 
@@ -1763,7 +1763,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
        ip_mc_inc_group(in_dev, addr);
        err = 0;
 done:
-       rtnl_shunlock();
+       rtnl_unlock();
        return err;
 }
 
@@ -1837,7 +1837,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
        if (!MULTICAST(addr))
                return -EINVAL;
 
-       rtnl_shlock();
+       rtnl_lock();
 
        imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr;
        imr.imr_address.s_addr = mreqs->imr_interface;
@@ -1947,7 +1947,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
        ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, 
                &mreqs->imr_sourceaddr, 1);
 done:
-       rtnl_shunlock();
+       rtnl_unlock();
        if (leavegroup)
                return ip_mc_leave_group(sk, &imr);
        return err;
@@ -1970,7 +1970,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
            msf->imsf_fmode != MCAST_EXCLUDE)
                return -EINVAL;
 
-       rtnl_shlock();
+       rtnl_lock();
 
        imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
        imr.imr_address.s_addr = msf->imsf_interface;
@@ -2030,7 +2030,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
        pmc->sfmode = msf->imsf_fmode;
        err = 0;
 done:
-       rtnl_shunlock();
+       rtnl_unlock();
        if (leavegroup)
                err = ip_mc_leave_group(sk, &imr);
        return err;
@@ -2050,7 +2050,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
        if (!MULTICAST(addr))
                return -EINVAL;
 
-       rtnl_shlock();
+       rtnl_lock();
 
        imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
        imr.imr_address.s_addr = msf->imsf_interface;
@@ -2072,7 +2072,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
                goto done;
        msf->imsf_fmode = pmc->sfmode;
        psl = pmc->sflist;
-       rtnl_shunlock();
+       rtnl_unlock();
        if (!psl) {
                len = 0;
                count = 0;
@@ -2091,7 +2091,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
                return -EFAULT;
        return 0;
 done:
-       rtnl_shunlock();
+       rtnl_unlock();
        return err;
 }
 
@@ -2112,7 +2112,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
        if (!MULTICAST(addr))
                return -EINVAL;
 
-       rtnl_shlock();
+       rtnl_lock();
 
        err = -EADDRNOTAVAIL;
 
@@ -2125,7 +2125,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
                goto done;
        gsf->gf_fmode = pmc->sfmode;
        psl = pmc->sflist;
-       rtnl_shunlock();
+       rtnl_unlock();
        count = psl ? psl->sl_count : 0;
        copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
        gsf->gf_numsrc = count;
@@ -2146,7 +2146,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
        }
        return 0;
 done:
-       rtnl_shunlock();
+       rtnl_unlock();
        return err;
 }
 
index ae20281..9a01bb8 100644 (file)
@@ -648,3 +648,52 @@ void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
 }
 
 EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr);
+
+int inet_csk_ctl_sock_create(struct socket **sock, unsigned short family,
+                            unsigned short type, unsigned char protocol)
+{
+       int rc = sock_create_kern(family, type, protocol, sock);
+
+       if (rc == 0) {
+               (*sock)->sk->sk_allocation = GFP_ATOMIC;
+               inet_sk((*sock)->sk)->uc_ttl = -1;
+               /*
+                * Unhash it so that IP input processing does not even see it,
+                * we do not wish this socket to see incoming packets.
+                */
+               (*sock)->sk->sk_prot->unhash((*sock)->sk);
+       }
+       return rc;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_ctl_sock_create);
+
+#ifdef CONFIG_COMPAT
+int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname,
+                              char __user *optval, int __user *optlen)
+{
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (icsk->icsk_af_ops->compat_getsockopt != NULL)
+               return icsk->icsk_af_ops->compat_getsockopt(sk, level, optname,
+                                                           optval, optlen);
+       return icsk->icsk_af_ops->getsockopt(sk, level, optname,
+                                            optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt);
+
+int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
+                              char __user *optval, int optlen)
+{
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (icsk->icsk_af_ops->compat_setsockopt != NULL)
+               return icsk->icsk_af_ops->compat_setsockopt(sk, level, optname,
+                                                           optval, optlen);
+       return icsk->icsk_af_ops->setsockopt(sk, level, optname,
+                                            optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt);
+#endif
index 2bf8d78..12e0bf1 100644 (file)
@@ -50,6 +50,7 @@
 #define IP_CMSG_TOS            4
 #define IP_CMSG_RECVOPTS       8
 #define IP_CMSG_RETOPTS                16
+#define IP_CMSG_PASSSEC                32
 
 /*
  *     SOL_IP control messages.
@@ -109,6 +110,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
        put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
 }
 
+static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
+{
+       char *secdata;
+       u32 seclen;
+       int err;
+
+       err = security_socket_getpeersec_dgram(skb, &secdata, &seclen);
+       if (err)
+               return;
+
+       put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
+}
+
 
 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 {
@@ -138,6 +152,11 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 
        if (flags & 1)
                ip_cmsg_recv_retopts(msg, skb);
+       if ((flags>>=1) == 0)
+               return;
+
+       if (flags & 1)
+               ip_cmsg_recv_security(msg, skb);
 }
 
 int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -380,20 +399,19 @@ out:
  *     an IP socket.
  */
 
-int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen)
+static int do_ip_setsockopt(struct sock *sk, int level,
+               int optname, char __user *optval, int optlen)
 {
        struct inet_sock *inet = inet_sk(sk);
        int val=0,err;
 
-       if (level != SOL_IP)
-               return -ENOPROTOOPT;
-
        if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | 
                            (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | 
                            (1<<IP_RETOPTS) | (1<<IP_TOS) | 
                            (1<<IP_TTL) | (1<<IP_HDRINCL) | 
                            (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 
-                           (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || 
+                           (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
+                           (1<<IP_PASSSEC))) ||
                                optname == IP_MULTICAST_TTL || 
                                optname == IP_MULTICAST_LOOP) { 
                if (optlen >= sizeof(int)) {
@@ -478,6 +496,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                        else
                                inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
                        break;
+               case IP_PASSSEC:
+                       if (val)
+                               inet->cmsg_flags |= IP_CMSG_PASSSEC;
+                       else
+                               inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
+                       break;
                case IP_TOS:    /* This sets both TOS and Precedence */
                        if (sk->sk_type == SOCK_STREAM) {
                                val &= ~3;
@@ -849,12 +873,7 @@ mc_msf_out:
                        break;
 
                default:
-#ifdef CONFIG_NETFILTER
-                       err = nf_setsockopt(sk, PF_INET, optname, optval, 
-                                           optlen);
-#else
                        err = -ENOPROTOOPT;
-#endif
                        break;
        }
        release_sock(sk);
@@ -865,12 +884,68 @@ e_inval:
        return -EINVAL;
 }
 
+int ip_setsockopt(struct sock *sk, int level,
+               int optname, char __user *optval, int optlen)
+{
+       int err;
+
+       if (level != SOL_IP)
+               return -ENOPROTOOPT;
+
+       err = do_ip_setsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
+               optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY
+#ifdef CONFIG_IP_MROUTE
+               && (optname < MRT_BASE || optname > (MRT_BASE + 10))
+#endif
+          ) {
+               lock_sock(sk);
+               err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
+               release_sock(sk);
+       }
+#endif
+       return err;
+}
+
+#ifdef CONFIG_COMPAT
+int compat_ip_setsockopt(struct sock *sk, int level, int optname,
+                        char __user *optval, int optlen)
+{
+       int err;
+
+       if (level != SOL_IP)
+               return -ENOPROTOOPT;
+
+       err = do_ip_setsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
+           optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY
+#ifdef CONFIG_IP_MROUTE
+           && (optname < MRT_BASE || optname > (MRT_BASE + 10))
+#endif
+          ) {
+               lock_sock(sk);
+               err = compat_nf_setsockopt(sk, PF_INET, optname,
+                                          optval, optlen);
+               release_sock(sk);
+       }
+#endif
+       return err;
+}
+
+EXPORT_SYMBOL(compat_ip_setsockopt);
+#endif
+
 /*
  *     Get the options. Note for future reference. The GET of IP options gets the
  *     _received_ ones. The set sets the _sent_ ones.
  */
 
-int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen)
+static int do_ip_getsockopt(struct sock *sk, int level, int optname,
+               char __user *optval, int __user *optlen)
 {
        struct inet_sock *inet = inet_sk(sk);
        int val;
@@ -932,6 +1007,9 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
                case IP_RETOPTS:
                        val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
                        break;
+               case IP_PASSSEC:
+                       val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
+                       break;
                case IP_TOS:
                        val = inet->tos;
                        break;
@@ -1051,17 +1129,8 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
                        val = inet->freebind; 
                        break; 
                default:
-#ifdef CONFIG_NETFILTER
-                       val = nf_getsockopt(sk, PF_INET, optname, optval, 
-                                           &len);
-                       release_sock(sk);
-                       if (val >= 0)
-                               val = put_user(len, optlen);
-                       return val;
-#else
                        release_sock(sk);
                        return -ENOPROTOOPT;
-#endif
        }
        release_sock(sk);
        
@@ -1082,6 +1151,67 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
        return 0;
 }
 
+int ip_getsockopt(struct sock *sk, int level,
+               int optname, char __user *optval, int __user *optlen)
+{
+       int err;
+
+       err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
+#ifdef CONFIG_IP_MROUTE
+               && (optname < MRT_BASE || optname > MRT_BASE+10)
+#endif
+          ) {
+               int len;
+
+               if(get_user(len,optlen))
+                       return -EFAULT;
+
+               lock_sock(sk);
+               err = nf_getsockopt(sk, PF_INET, optname, optval,
+                               &len);
+               release_sock(sk);
+               if (err >= 0)
+                       err = put_user(len, optlen);
+               return err;
+       }
+#endif
+       return err;
+}
+
+#ifdef CONFIG_COMPAT
+int compat_ip_getsockopt(struct sock *sk, int level, int optname,
+                        char __user *optval, int __user *optlen)
+{
+       int err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
+#ifdef CONFIG_IP_MROUTE
+           && (optname < MRT_BASE || optname > MRT_BASE+10)
+#endif
+          ) {
+               int len;
+
+               if (get_user(len, optlen))
+                       return -EFAULT;
+
+               lock_sock(sk);
+               err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len);
+               release_sock(sk);
+               if (err >= 0)
+                       err = put_user(len, optlen);
+               return err;
+       }
+#endif
+       return err;
+}
+
+EXPORT_SYMBOL(compat_ip_getsockopt);
+#endif
+
 EXPORT_SYMBOL(ip_cmsg_recv);
 
 EXPORT_SYMBOL(ip_getsockopt);
index d64e2ec..c95020f 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/rtnetlink.h>
+#include <linux/mutex.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/icmp.h>
@@ -36,7 +37,7 @@ struct ipcomp_tfms {
        int users;
 };
 
-static DECLARE_MUTEX(ipcomp_resource_sem);
+static DEFINE_MUTEX(ipcomp_resource_mutex);
 static void **ipcomp_scratches;
 static int ipcomp_scratch_users;
 static LIST_HEAD(ipcomp_tfms_list);
@@ -253,7 +254,7 @@ error:
 }
 
 /*
- * Must be protected by xfrm_cfg_sem.  State and tunnel user references are
+ * Must be protected by xfrm_cfg_mutex.  State and tunnel user references are
  * always incremented on success.
  */
 static int ipcomp_tunnel_attach(struct xfrm_state *x)
@@ -411,9 +412,9 @@ static void ipcomp_destroy(struct xfrm_state *x)
        if (!ipcd)
                return;
        xfrm_state_delete_tunnel(x);
-       down(&ipcomp_resource_sem);
+       mutex_lock(&ipcomp_resource_mutex);
        ipcomp_free_data(ipcd);
-       up(&ipcomp_resource_sem);
+       mutex_unlock(&ipcomp_resource_mutex);
        kfree(ipcd);
 }
 
@@ -440,14 +441,14 @@ static int ipcomp_init_state(struct xfrm_state *x)
        if (x->props.mode)
                x->props.header_len += sizeof(struct iphdr);
 
-       down(&ipcomp_resource_sem);
+       mutex_lock(&ipcomp_resource_mutex);
        if (!ipcomp_alloc_scratches())
                goto error;
 
        ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name);
        if (!ipcd->tfms)
                goto error;
-       up(&ipcomp_resource_sem);
+       mutex_unlock(&ipcomp_resource_mutex);
 
        if (x->props.mode) {
                err = ipcomp_tunnel_attach(x);
@@ -464,10 +465,10 @@ out:
        return err;
 
 error_tunnel:
-       down(&ipcomp_resource_sem);
+       mutex_lock(&ipcomp_resource_mutex);
 error:
        ipcomp_free_data(ipcd);
-       up(&ipcomp_resource_sem);
+       mutex_unlock(&ipcomp_resource_mutex);
        kfree(ipcd);
        goto out;
 }
index bb3613e..cb8a92f 100644 (file)
@@ -186,7 +186,7 @@ static int __init ic_open_devs(void)
        unsigned short oflags;
 
        last = &ic_first_dev;
-       rtnl_shlock();
+       rtnl_lock();
 
        /* bring loopback device up first */
        if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0)
@@ -215,7 +215,7 @@ static int __init ic_open_devs(void)
                                continue;
                        }
                        if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) {
-                               rtnl_shunlock();
+                               rtnl_unlock();
                                return -1;
                        }
                        d->dev = dev;
@@ -232,7 +232,7 @@ static int __init ic_open_devs(void)
                                dev->name, able, d->xid));
                }
        }
-       rtnl_shunlock();
+       rtnl_unlock();
 
        *last = NULL;
 
@@ -251,7 +251,7 @@ static void __init ic_close_devs(void)
        struct ic_device *d, *next;
        struct net_device *dev;
 
-       rtnl_shlock();
+       rtnl_lock();
        next = ic_first_dev;
        while ((d = next)) {
                next = d->next;
@@ -262,7 +262,7 @@ static void __init ic_close_devs(void)
                }
                kfree(d);
        }
-       rtnl_shunlock();
+       rtnl_unlock();
 }
 
 /*
index 5c94c22..717ab7d 100644 (file)
@@ -415,10 +415,10 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
                        return -ENOBUFS;
                break;
        case 0:
-               dev=ip_dev_find(vifc->vifc_lcl_addr.s_addr);
+               dev = ip_dev_find(vifc->vifc_lcl_addr.s_addr);
                if (!dev)
                        return -EADDRNOTAVAIL;
-               __dev_put(dev);
+               dev_put(dev);
                break;
        default:
                return -EINVAL;
index 9b176a9..e775233 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 
 #include <net/ip_vs.h>
 
@@ -40,7 +41,7 @@ EXPORT_SYMBOL(register_ip_vs_app_inc);
 
 /* ipvs application list head */
 static LIST_HEAD(ip_vs_app_list);
-static DECLARE_MUTEX(__ip_vs_app_mutex);
+static DEFINE_MUTEX(__ip_vs_app_mutex);
 
 
 /*
@@ -173,11 +174,11 @@ register_ip_vs_app_inc(struct ip_vs_app *app, __u16 proto, __u16 port)
 {
        int result;
 
-       down(&__ip_vs_app_mutex);
+       mutex_lock(&__ip_vs_app_mutex);
 
        result = ip_vs_app_inc_new(app, proto, port);
 
-       up(&__ip_vs_app_mutex);
+       mutex_unlock(&__ip_vs_app_mutex);
 
        return result;
 }
@@ -191,11 +192,11 @@ int register_ip_vs_app(struct ip_vs_app *app)
        /* increase the module use count */
        ip_vs_use_count_inc();
 
-       down(&__ip_vs_app_mutex);
+       mutex_lock(&__ip_vs_app_mutex);
 
        list_add(&app->a_list, &ip_vs_app_list);
 
-       up(&__ip_vs_app_mutex);
+       mutex_unlock(&__ip_vs_app_mutex);
 
        return 0;
 }
@@ -209,7 +210,7 @@ void unregister_ip_vs_app(struct ip_vs_app *app)
 {
        struct ip_vs_app *inc, *nxt;
 
-       down(&__ip_vs_app_mutex);
+       mutex_lock(&__ip_vs_app_mutex);
 
        list_for_each_entry_safe(inc, nxt, &app->incs_list, a_list) {
                ip_vs_app_inc_release(inc);
@@ -217,7 +218,7 @@ void unregister_ip_vs_app(struct ip_vs_app *app)
 
        list_del(&app->a_list);
 
-       up(&__ip_vs_app_mutex);
+       mutex_unlock(&__ip_vs_app_mutex);
 
        /* decrease the module use count */
        ip_vs_use_count_dec();
@@ -498,7 +499,7 @@ static struct ip_vs_app *ip_vs_app_idx(loff_t pos)
 
 static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       down(&__ip_vs_app_mutex);
+       mutex_lock(&__ip_vs_app_mutex);
 
        return *pos ? ip_vs_app_idx(*pos - 1) : SEQ_START_TOKEN;
 }
@@ -530,7 +531,7 @@ static void *ip_vs_app_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 
 static void ip_vs_app_seq_stop(struct seq_file *seq, void *v)
 {
-       up(&__ip_vs_app_mutex);
+       mutex_unlock(&__ip_vs_app_mutex);
 }
 
 static int ip_vs_app_seq_show(struct seq_file *seq, void *v)
index db78303..882b842 100644 (file)
@@ -168,6 +168,26 @@ config IP_NF_PPTP
          If you want to compile it as a module, say M here and read
          Documentation/modules.txt.  If unsure, say `N'.
 
+config IP_NF_H323
+       tristate  'H.323 protocol support'
+       depends on IP_NF_CONNTRACK
+       help
+         H.323 is a VoIP signalling protocol from ITU-T. As one of the most
+         important VoIP protocols, it is widely used by voice hardware and
+         software including voice gateways, IP phones, Netmeeting, OpenPhone,
+         Gnomemeeting, etc.
+
+         With this module you can support H.323 on a connection tracking/NAT
+         firewall.
+
+         This module supports RAS, Fast-start, H.245 tunnelling, RTP/RTCP
+         and T.120 based data and applications including audio, video, FAX,
+         chat, whiteboard, file transfer, etc. For more information, please
+         see http://nath323.sourceforge.net/.
+
+         If you want to compile it as a module, say 'M' here and read
+         Documentation/modules.txt.  If unsure, say 'N'.
+
 config IP_NF_QUEUE
        tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
        help
@@ -303,16 +323,6 @@ config IP_NF_MATCH_HASHLIMIT
          destination IP' or `500pps from any given source IP'  with a single
          IPtables rule.
 
-config IP_NF_MATCH_POLICY
-       tristate "IPsec policy match support"
-       depends on IP_NF_IPTABLES && XFRM
-       help
-         Policy matching allows you to match packets based on the
-         IPsec policy that was used during decapsulation/will
-         be used during encapsulation.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 # `filter', generic and specific targets
 config IP_NF_FILTER
        tristate "Packet filtering"
@@ -494,6 +504,12 @@ config IP_NF_NAT_PPTP
        default IP_NF_NAT if IP_NF_PPTP=y
        default m if IP_NF_PPTP=m
 
+config IP_NF_NAT_H323
+       tristate
+       depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
+       default IP_NF_NAT if IP_NF_H323=y
+       default m if IP_NF_H323=m
+
 # mangle + specific targets
 config IP_NF_MANGLE
        tristate "Packet mangling"
index e5c5b32..f2cd9a6 100644 (file)
@@ -10,6 +10,9 @@ iptable_nat-objs      := ip_nat_rule.o ip_nat_standalone.o
 ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o
 ip_nat_pptp-objs       := ip_nat_helper_pptp.o ip_nat_proto_gre.o
 
+ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ip_conntrack_helper_h323_asn1.o
+ip_nat_h323-objs := ip_nat_helper_h323.o
+
 # connection tracking
 obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
 obj-$(CONFIG_IP_NF_NAT) += ip_nat.o
@@ -22,6 +25,7 @@ obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o
 obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o
 
 # connection tracking helpers
+obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
 obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
 obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
 obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
@@ -30,6 +34,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
 obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
 
 # NAT helpers 
+obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
 obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
 obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
 obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
@@ -57,7 +62,6 @@ obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
-obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
 
 # targets
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
index 7d7ab94..f7efb3f 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_arp/arp_tables.h>
@@ -208,6 +208,7 @@ static unsigned int arpt_error(struct sk_buff **pskb,
                               const struct net_device *in,
                               const struct net_device *out,
                               unsigned int hooknum,
+                              const struct xt_target *target,
                               const void *targinfo,
                               void *userinfo)
 {
@@ -300,6 +301,7 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
                                verdict = t->u.kernel.target->target(pskb,
                                                                     in, out,
                                                                     hook,
+                                                                    t->u.kernel.target,
                                                                     t->data,
                                                                     userdata);
 
@@ -480,26 +482,31 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
        }
        t->u.kernel.target = target;
 
+       ret = xt_check_target(target, NF_ARP, t->u.target_size - sizeof(*t),
+                             name, e->comefrom, 0, 0);
+       if (ret)
+               goto err;
+
        if (t->u.kernel.target == &arpt_standard_target) {
                if (!standard_check(t, size)) {
                        ret = -EINVAL;
                        goto out;
                }
        } else if (t->u.kernel.target->checkentry
-                  && !t->u.kernel.target->checkentry(name, e, t->data,
+                  && !t->u.kernel.target->checkentry(name, e, target, t->data,
                                                      t->u.target_size
                                                      - sizeof(*t),
                                                      e->comefrom)) {
-               module_put(t->u.kernel.target->me);
                duprintf("arp_tables: check failed for `%s'.\n",
                         t->u.kernel.target->name);
                ret = -EINVAL;
-               goto out;
+               goto err;
        }
 
        (*i)++;
        return 0;
-
+err:
+       module_put(t->u.kernel.target->me);
 out:
        return ret;
 }
@@ -555,7 +562,7 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
 
        t = arpt_get_target(e);
        if (t->u.kernel.target->destroy)
-               t->u.kernel.target->destroy(t->data,
+               t->u.kernel.target->destroy(t->u.kernel.target, t->data,
                                            t->u.target_size - sizeof(*t));
        module_put(t->u.kernel.target->me);
        return 0;
@@ -1138,11 +1145,13 @@ void arpt_unregister_table(struct arpt_table *table)
 /* The built-in targets: standard (NULL) and error. */
 static struct arpt_target arpt_standard_target = {
        .name           = ARPT_STANDARD_TARGET,
+       .targetsize     = sizeof(int),
 };
 
 static struct arpt_target arpt_error_target = {
        .name           = ARPT_ERROR_TARGET,
        .target         = arpt_error,
+       .targetsize     = ARPT_FUNCTION_MAXNAMELEN,
 };
 
 static struct nf_sockopt_ops arpt_sockopts = {
index c97650a..0f2a953 100644 (file)
@@ -8,9 +8,10 @@ MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
 MODULE_DESCRIPTION("arptables arp payload mangle target");
 
 static unsigned int
-target(struct sk_buff **pskb, const struct net_device *in,
-   const struct net_device *out, unsigned int hooknum, const void *targinfo,
-   void *userinfo)
+target(struct sk_buff **pskb,
+       const struct net_device *in, const struct net_device *out,
+       unsigned int hooknum, const struct xt_target *target,
+       const void *targinfo, void *userinfo)
 {
        const struct arpt_mangle *mangle = targinfo;
        struct arphdr *arp;
@@ -65,8 +66,8 @@ target(struct sk_buff **pskb, const struct net_device *in,
 }
 
 static int
-checkentry(const char *tablename, const void *e, void *targinfo,
-   unsigned int targinfosize, unsigned int hook_mask)
+checkentry(const char *tablename, const void *e, const struct xt_target *target,
+           void *targinfo, unsigned int targinfosize, unsigned int hook_mask)
 {
        const struct arpt_mangle *mangle = targinfo;
 
@@ -80,12 +81,12 @@ checkentry(const char *tablename, const void *e, void *targinfo,
        return 1;
 }
 
-static struct arpt_target arpt_mangle_reg
-= {
-        .name          = "mangle",
-        .target                = target,
-        .checkentry    = checkentry,
-        .me            = THIS_MODULE,
+static struct arpt_target arpt_mangle_reg = {
+       .name           = "mangle",
+       .target         = target,
+       .targetsize     = sizeof(struct arpt_mangle),
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
 };
 
 static int __init init(void)
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
new file mode 100644 (file)
index 0000000..20da673
--- /dev/null
@@ -0,0 +1,1731 @@
+/*
+ * H.323 connection tracking helper
+ *
+ * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ *
+ * This source code is licensed under General Public License version 2.
+ *
+ * Based on the 'brute force' H.323 connection tracking module by
+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * For more information, please see http://nath323.sourceforge.net/
+ *
+ * Changes:
+ *     2006-02-01 - initial version 0.1
+ *
+ *     2006-02-20 - version 0.2
+ *       1. Changed source format to follow kernel conventions
+ *       2. Deleted some unnecessary structures
+ *       3. Minor fixes
+ *
+ *     2006-03-10 - version 0.3
+ *       1. Added support for multiple TPKTs in one packet (suggested by
+ *          Patrick McHardy)
+ *       2. Avoid excessive stack usage (based on Patrick McHardy's patch)
+ *       3. Added support for non-linear skb (based on Patrick McHardy's patch)
+ *       4. Fixed missing H.245 module owner (Patrick McHardy)
+ *       5. Avoid long RAS expectation chains (Patrick McHardy)
+ *       6. Fixed incorrect __exit attribute (Patrick McHardy)
+ *       7. Eliminated unnecessary return code
+ *       8. Fixed incorrect use of NAT data from conntrack code (suggested by
+ *          Patrick McHardy)
+ *       9. Fixed TTL calculation error in RCF
+ *       10. Added TTL support in RRQ
+ *       11. Better support for separate TPKT header and data
+ *
+ *     2006-03-15 - version 0.4
+ *       1. Added support for T.120 channels
+ *       2. Added parameter gkrouted_only (suggested by Patrick McHardy)
+ *       3. Splitted ASN.1 code and data (suggested by Patrick McHardy)
+ *       4. Sort ASN.1 data to avoid forwarding declarations (suggested by
+ *          Patrick McHardy)
+ *       5. Reset next TPKT data length in get_tpkt_data()
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <net/tcp.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+#include <linux/moduleparam.h>
+
+#include "ip_conntrack_helper_h323_asn1.h"
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Parameters */
+static int gkrouted_only = 1;
+module_param(gkrouted_only, int, 0600);
+MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");
+
+/* Hooks for NAT */
+int (*set_h245_addr_hook) (struct sk_buff ** pskb,
+                          unsigned char **data, int dataoff,
+                          H245_TransportAddress * addr,
+                          u_int32_t ip, u_int16_t port);
+int (*set_h225_addr_hook) (struct sk_buff ** pskb,
+                          unsigned char **data, int dataoff,
+                          TransportAddress * addr,
+                          u_int32_t ip, u_int16_t port);
+int (*set_sig_addr_hook) (struct sk_buff ** pskb,
+                         struct ip_conntrack * ct,
+                         enum ip_conntrack_info ctinfo,
+                         unsigned char **data,
+                         TransportAddress * addr, int count);
+int (*set_ras_addr_hook) (struct sk_buff ** pskb,
+                         struct ip_conntrack * ct,
+                         enum ip_conntrack_info ctinfo,
+                         unsigned char **data,
+                         TransportAddress * addr, int count);
+int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
+                         struct ip_conntrack * ct,
+                         enum ip_conntrack_info ctinfo,
+                         unsigned char **data, int dataoff,
+                         H245_TransportAddress * addr,
+                         u_int16_t port, u_int16_t rtp_port,
+                         struct ip_conntrack_expect * rtp_exp,
+                         struct ip_conntrack_expect * rtcp_exp);
+int (*nat_t120_hook) (struct sk_buff ** pskb,
+                     struct ip_conntrack * ct,
+                     enum ip_conntrack_info ctinfo,
+                     unsigned char **data, int dataoff,
+                     H245_TransportAddress * addr, u_int16_t port,
+                     struct ip_conntrack_expect * exp);
+int (*nat_h245_hook) (struct sk_buff ** pskb,
+                     struct ip_conntrack * ct,
+                     enum ip_conntrack_info ctinfo,
+                     unsigned char **data, int dataoff,
+                     TransportAddress * addr, u_int16_t port,
+                     struct ip_conntrack_expect * exp);
+int (*nat_q931_hook) (struct sk_buff ** pskb,
+                     struct ip_conntrack * ct,
+                     enum ip_conntrack_info ctinfo,
+                     unsigned char **data, TransportAddress * addr, int idx,
+                     u_int16_t port, struct ip_conntrack_expect * exp);
+
+
+static DEFINE_SPINLOCK(ip_h323_lock);
+static char *h323_buffer;
+
+/****************************************************************************/
+static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct,
+                        enum ip_conntrack_info ctinfo,
+                        unsigned char **data, int *datalen, int *dataoff)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       struct tcphdr _tcph, *th;
+       int tcpdatalen;
+       int tcpdataoff;
+       unsigned char *tpkt;
+       int tpktlen;
+       int tpktoff;
+
+       /* Get TCP header */
+       th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
+                               sizeof(_tcph), &_tcph);
+       if (th == NULL)
+               return 0;
+
+       /* Get TCP data offset */
+       tcpdataoff = (*pskb)->nh.iph->ihl * 4 + th->doff * 4;
+
+       /* Get TCP data length */
+       tcpdatalen = (*pskb)->len - tcpdataoff;
+       if (tcpdatalen <= 0)    /* No TCP data */
+               goto clear_out;
+
+       if (*data == NULL) {    /* first TPKT */
+               /* Get first TPKT pointer */
+               tpkt = skb_header_pointer(*pskb, tcpdataoff, tcpdatalen,
+                                         h323_buffer);
+               BUG_ON(tpkt == NULL);
+
+               /* Validate TPKT identifier */
+               if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) {
+                       /* Netmeeting sends TPKT header and data separately */
+                       if (info->tpkt_len[dir] > 0) {
+                               DEBUGP("ip_ct_h323: previous packet "
+                                      "indicated separate TPKT data of %hu "
+                                      "bytes\n", info->tpkt_len[dir]);
+                               if (info->tpkt_len[dir] <= tcpdatalen) {
+                                       /* Yes, there was a TPKT header
+                                        * received */
+                                       *data = tpkt;
+                                       *datalen = info->tpkt_len[dir];
+                                       *dataoff = 0;
+                                       goto out;
+                               }
+
+                               /* Fragmented TPKT */
+                               if (net_ratelimit())
+                                       printk("ip_ct_h323: "
+                                              "fragmented TPKT\n");
+                               goto clear_out;
+                       }
+
+                       /* It is not even a TPKT */
+                       return 0;
+               }
+               tpktoff = 0;
+       } else {                /* Next TPKT */
+               tpktoff = *dataoff + *datalen;
+               tcpdatalen -= tpktoff;
+               if (tcpdatalen <= 4)    /* No more TPKT */
+                       goto clear_out;
+               tpkt = *data + *datalen;
+
+               /* Validate TPKT identifier */
+               if (tpkt[0] != 0x03 || tpkt[1] != 0)
+                       goto clear_out;
+       }
+
+       /* Validate TPKT length */
+       tpktlen = tpkt[2] * 256 + tpkt[3];
+       if (tpktlen > tcpdatalen) {
+               if (tcpdatalen == 4) {  /* Separate TPKT header */
+                       /* Netmeeting sends TPKT header and data separately */
+                       DEBUGP("ip_ct_h323: separate TPKT header indicates "
+                              "there will be TPKT data of %hu bytes\n",
+                              tpktlen - 4);
+                       info->tpkt_len[dir] = tpktlen - 4;
+                       return 0;
+               }
+
+               if (net_ratelimit())
+                       printk("ip_ct_h323: incomplete TPKT (fragmented?)\n");
+               goto clear_out;
+       }
+
+       /* This is the encapsulated data */
+       *data = tpkt + 4;
+       *datalen = tpktlen - 4;
+       *dataoff = tpktoff + 4;
+
+      out:
+       /* Clear TPKT length */
+       info->tpkt_len[dir] = 0;
+       return 1;
+
+      clear_out:
+       info->tpkt_len[dir] = 0;
+       return 0;
+}
+
+/****************************************************************************/
+int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
+                 u_int32_t * ip, u_int16_t * port)
+{
+       unsigned char *p;
+
+       if (addr->choice != eH245_TransportAddress_unicastAddress ||
+           addr->unicastAddress.choice != eUnicastAddress_iPAddress)
+               return 0;
+
+       p = data + addr->unicastAddress.iPAddress.network;
+       *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
+       *port = (p[4] << 8) | (p[5]);
+
+       return 1;
+}
+
+/****************************************************************************/
+static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
+                          enum ip_conntrack_info ctinfo,
+                          unsigned char **data, int dataoff,
+                          H245_TransportAddress * addr)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       int ret = 0;
+       u_int32_t ip;
+       u_int16_t port;
+       u_int16_t rtp_port;
+       struct ip_conntrack_expect *rtp_exp;
+       struct ip_conntrack_expect *rtcp_exp;
+
+       /* Read RTP or RTCP address */
+       if (!get_h245_addr(*data, addr, &ip, &port) ||
+           ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
+               return 0;
+
+       /* RTP port is even */
+       rtp_port = port & (~1);
+
+       /* Create expect for RTP */
+       if ((rtp_exp = ip_conntrack_expect_alloc(ct)) == NULL)
+               return -1;
+       rtp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+       rtp_exp->tuple.src.u.udp.port = 0;
+       rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+       rtp_exp->tuple.dst.u.udp.port = htons(rtp_port);
+       rtp_exp->tuple.dst.protonum = IPPROTO_UDP;
+       rtp_exp->mask.src.ip = 0xFFFFFFFF;
+       rtp_exp->mask.src.u.udp.port = 0;
+       rtp_exp->mask.dst.ip = 0xFFFFFFFF;
+       rtp_exp->mask.dst.u.udp.port = 0xFFFF;
+       rtp_exp->mask.dst.protonum = 0xFF;
+       rtp_exp->flags = 0;
+
+       /* Create expect for RTCP */
+       if ((rtcp_exp = ip_conntrack_expect_alloc(ct)) == NULL) {
+               ip_conntrack_expect_put(rtp_exp);
+               return -1;
+       }
+       rtcp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+       rtcp_exp->tuple.src.u.udp.port = 0;
+       rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+       rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1);
+       rtcp_exp->tuple.dst.protonum = IPPROTO_UDP;
+       rtcp_exp->mask.src.ip = 0xFFFFFFFF;
+       rtcp_exp->mask.src.u.udp.port = 0;
+       rtcp_exp->mask.dst.ip = 0xFFFFFFFF;
+       rtcp_exp->mask.dst.u.udp.port = 0xFFFF;
+       rtcp_exp->mask.dst.protonum = 0xFF;
+       rtcp_exp->flags = 0;
+
+       if (ct->tuplehash[dir].tuple.src.ip !=
+           ct->tuplehash[!dir].tuple.dst.ip && nat_rtp_rtcp_hook) {
+               /* NAT needed */
+               ret = nat_rtp_rtcp_hook(pskb, ct, ctinfo, data, dataoff,
+                                       addr, port, rtp_port, rtp_exp,
+                                       rtcp_exp);
+       } else {                /* Conntrack only */
+               rtp_exp->expectfn = NULL;
+               rtcp_exp->expectfn = NULL;
+
+               if (ip_conntrack_expect_related(rtp_exp) == 0) {
+                       if (ip_conntrack_expect_related(rtcp_exp) == 0) {
+                               DEBUGP("ip_ct_h323: expect RTP "
+                                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                                      NIPQUAD(rtp_exp->tuple.src.ip),
+                                      ntohs(rtp_exp->tuple.src.u.udp.port),
+                                      NIPQUAD(rtp_exp->tuple.dst.ip),
+                                      ntohs(rtp_exp->tuple.dst.u.udp.port));
+                               DEBUGP("ip_ct_h323: expect RTCP "
+                                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                                      NIPQUAD(rtcp_exp->tuple.src.ip),
+                                      ntohs(rtcp_exp->tuple.src.u.udp.port),
+                                      NIPQUAD(rtcp_exp->tuple.dst.ip),
+                                      ntohs(rtcp_exp->tuple.dst.u.udp.port));
+                       } else {
+                               ip_conntrack_unexpect_related(rtp_exp);
+                               ret = -1;
+                       }
+               } else
+                       ret = -1;
+       }
+
+       ip_conntrack_expect_put(rtp_exp);
+       ip_conntrack_expect_put(rtcp_exp);
+
+       return ret;
+}
+
+/****************************************************************************/
+static int expect_t120(struct sk_buff **pskb,
+                      struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, int dataoff,
+                      H245_TransportAddress * addr)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       int ret = 0;
+       u_int32_t ip;
+       u_int16_t port;
+       struct ip_conntrack_expect *exp = NULL;
+
+       /* Read T.120 address */
+       if (!get_h245_addr(*data, addr, &ip, &port) ||
+           ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
+               return 0;
+
+       /* Create expect for T.120 connections */
+       if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+               return -1;
+       exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+       exp->tuple.src.u.tcp.port = 0;
+       exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+       exp->tuple.dst.u.tcp.port = htons(port);
+       exp->tuple.dst.protonum = IPPROTO_TCP;
+       exp->mask.src.ip = 0xFFFFFFFF;
+       exp->mask.src.u.tcp.port = 0;
+       exp->mask.dst.ip = 0xFFFFFFFF;
+       exp->mask.dst.u.tcp.port = 0xFFFF;
+       exp->mask.dst.protonum = 0xFF;
+       exp->flags = IP_CT_EXPECT_PERMANENT;    /* Accept multiple channels */
+
+       if (ct->tuplehash[dir].tuple.src.ip !=
+           ct->tuplehash[!dir].tuple.dst.ip && nat_t120_hook) {
+               /* NAT needed */
+               ret = nat_t120_hook(pskb, ct, ctinfo, data, dataoff, addr,
+                                   port, exp);
+       } else {                /* Conntrack only */
+               exp->expectfn = NULL;
+               if (ip_conntrack_expect_related(exp) == 0) {
+                       DEBUGP("ip_ct_h323: expect T.120 "
+                              "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                              NIPQUAD(exp->tuple.src.ip),
+                              ntohs(exp->tuple.src.u.tcp.port),
+                              NIPQUAD(exp->tuple.dst.ip),
+                              ntohs(exp->tuple.dst.u.tcp.port));
+               } else
+                       ret = -1;
+       }
+
+       ip_conntrack_expect_put(exp);
+
+       return ret;
+}
+
+/****************************************************************************/
+static int process_h245_channel(struct sk_buff **pskb,
+                               struct ip_conntrack *ct,
+                               enum ip_conntrack_info ctinfo,
+                               unsigned char **data, int dataoff,
+                               H2250LogicalChannelParameters * channel)
+{
+       int ret;
+
+       if (channel->options & eH2250LogicalChannelParameters_mediaChannel) {
+               /* RTP */
+               ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+                                     &channel->mediaChannel);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (channel->
+           options & eH2250LogicalChannelParameters_mediaControlChannel) {
+               /* RTCP */
+               ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+                                     &channel->mediaControlChannel);
+               if (ret < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_olc(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, int dataoff,
+                      OpenLogicalChannel * olc)
+{
+       int ret;
+
+       DEBUGP("ip_ct_h323: OpenLogicalChannel\n");
+
+       if (olc->forwardLogicalChannelParameters.multiplexParameters.choice ==
+           eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)
+       {
+               ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+                                          &olc->
+                                          forwardLogicalChannelParameters.
+                                          multiplexParameters.
+                                          h2250LogicalChannelParameters);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if ((olc->options &
+            eOpenLogicalChannel_reverseLogicalChannelParameters) &&
+           (olc->reverseLogicalChannelParameters.options &
+            eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters)
+           && (olc->reverseLogicalChannelParameters.multiplexParameters.
+               choice ==
+               eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
+       {
+               ret =
+                   process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+                                        &olc->
+                                        reverseLogicalChannelParameters.
+                                        multiplexParameters.
+                                        h2250LogicalChannelParameters);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if ((olc->options & eOpenLogicalChannel_separateStack) &&
+           olc->forwardLogicalChannelParameters.dataType.choice ==
+           eDataType_data &&
+           olc->forwardLogicalChannelParameters.dataType.data.application.
+           choice == eDataApplicationCapability_application_t120 &&
+           olc->forwardLogicalChannelParameters.dataType.data.application.
+           t120.choice == eDataProtocolCapability_separateLANStack &&
+           olc->separateStack.networkAddress.choice ==
+           eNetworkAccessParameters_networkAddress_localAreaAddress) {
+               ret = expect_t120(pskb, ct, ctinfo, data, dataoff,
+                                 &olc->separateStack.networkAddress.
+                                 localAreaAddress);
+               if (ret < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_olca(struct sk_buff **pskb, struct ip_conntrack *ct,
+                       enum ip_conntrack_info ctinfo,
+                       unsigned char **data, int dataoff,
+                       OpenLogicalChannelAck * olca)
+{
+       H2250LogicalChannelAckParameters *ack;
+       int ret;
+
+       DEBUGP("ip_ct_h323: OpenLogicalChannelAck\n");
+
+       if ((olca->options &
+            eOpenLogicalChannelAck_reverseLogicalChannelParameters) &&
+           (olca->reverseLogicalChannelParameters.options &
+            eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters)
+           && (olca->reverseLogicalChannelParameters.multiplexParameters.
+               choice ==
+               eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
+       {
+               ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
+                                          &olca->
+                                          reverseLogicalChannelParameters.
+                                          multiplexParameters.
+                                          h2250LogicalChannelParameters);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if ((olca->options &
+            eOpenLogicalChannelAck_forwardMultiplexAckParameters) &&
+           (olca->forwardMultiplexAckParameters.choice ==
+            eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters))
+       {
+               ack = &olca->forwardMultiplexAckParameters.
+                   h2250LogicalChannelAckParameters;
+               if (ack->options &
+                   eH2250LogicalChannelAckParameters_mediaChannel) {
+                       /* RTP */
+                       ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+                                             &ack->mediaChannel);
+                       if (ret < 0)
+                               return -1;
+               }
+
+               if (ack->options &
+                   eH2250LogicalChannelAckParameters_mediaControlChannel) {
+                       /* RTCP */
+                       ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
+                                             &ack->mediaControlChannel);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
+                       enum ip_conntrack_info ctinfo,
+                       unsigned char **data, int dataoff,
+                       MultimediaSystemControlMessage * mscm)
+{
+       switch (mscm->choice) {
+       case eMultimediaSystemControlMessage_request:
+               if (mscm->request.choice ==
+                   eRequestMessage_openLogicalChannel) {
+                       return process_olc(pskb, ct, ctinfo, data, dataoff,
+                                          &mscm->request.openLogicalChannel);
+               }
+               DEBUGP("ip_ct_h323: H.245 Request %d\n",
+                      mscm->request.choice);
+               break;
+       case eMultimediaSystemControlMessage_response:
+               if (mscm->response.choice ==
+                   eResponseMessage_openLogicalChannelAck) {
+                       return process_olca(pskb, ct, ctinfo, data, dataoff,
+                                           &mscm->response.
+                                           openLogicalChannelAck);
+               }
+               DEBUGP("ip_ct_h323: H.245 Response %d\n",
+                      mscm->response.choice);
+               break;
+       default:
+               DEBUGP("ip_ct_h323: H.245 signal %d\n", mscm->choice);
+               break;
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int h245_help(struct sk_buff **pskb, struct ip_conntrack *ct,
+                    enum ip_conntrack_info ctinfo)
+{
+       static MultimediaSystemControlMessage mscm;
+       unsigned char *data = NULL;
+       int datalen;
+       int dataoff;
+       int ret;
+
+       /* Until there's been traffic both ways, don't look in packets. */
+       if (ctinfo != IP_CT_ESTABLISHED
+           && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+               return NF_ACCEPT;
+       }
+       DEBUGP("ip_ct_h245: skblen = %u\n", (*pskb)->len);
+
+       spin_lock_bh(&ip_h323_lock);
+
+       /* Process each TPKT */
+       while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) {
+               DEBUGP("ip_ct_h245: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
+                      NIPQUAD((*pskb)->nh.iph->saddr),
+                      NIPQUAD((*pskb)->nh.iph->daddr), datalen);
+
+               /* Decode H.245 signal */
+               ret = DecodeMultimediaSystemControlMessage(data, datalen,
+                                                          &mscm);
+               if (ret < 0) {
+                       if (net_ratelimit())
+                               printk("ip_ct_h245: decoding error: %s\n",
+                                      ret == H323_ERROR_BOUND ?
+                                      "out of bound" : "out of range");
+                       /* We don't drop when decoding error */
+                       break;
+               }
+
+               /* Process H.245 signal */
+               if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0)
+                       goto drop;
+       }
+
+       spin_unlock_bh(&ip_h323_lock);
+       return NF_ACCEPT;
+
+      drop:
+       spin_unlock_bh(&ip_h323_lock);
+       if (net_ratelimit())
+               printk("ip_ct_h245: packet dropped\n");
+       return NF_DROP;
+}
+
+/****************************************************************************/
+static struct ip_conntrack_helper ip_conntrack_helper_h245 = {
+       .name = "H.245",
+       .me = THIS_MODULE,
+       .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */ ,
+       .timeout = 240,
+       .tuple = {.dst = {.protonum = IPPROTO_TCP}},
+       .mask = {.src = {.u = {0xFFFF}},
+                .dst = {.protonum = 0xFF}},
+       .help = h245_help
+};
+
+/****************************************************************************/
+void ip_conntrack_h245_expect(struct ip_conntrack *new,
+                             struct ip_conntrack_expect *this)
+{
+       write_lock_bh(&ip_conntrack_lock);
+       new->helper = &ip_conntrack_helper_h245;
+       write_unlock_bh(&ip_conntrack_lock);
+}
+
+/****************************************************************************/
+static int get_h225_addr(unsigned char *data, TransportAddress * addr,
+                        u_int32_t * ip, u_int16_t * port)
+{
+       unsigned char *p;
+
+       if (addr->choice != eTransportAddress_ipAddress)
+               return 0;
+
+       p = data + addr->ipAddress.ip;
+       *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
+       *port = (p[4] << 8) | (p[5]);
+
+       return 1;
+}
+
+/****************************************************************************/
+static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, int dataoff,
+                      TransportAddress * addr)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       int ret = 0;
+       u_int32_t ip;
+       u_int16_t port;
+       struct ip_conntrack_expect *exp = NULL;
+
+       /* Read h245Address */
+       if (!get_h225_addr(*data, addr, &ip, &port) ||
+           ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
+               return 0;
+
+       /* Create expect for h245 connection */
+       if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+               return -1;
+       exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+       exp->tuple.src.u.tcp.port = 0;
+       exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+       exp->tuple.dst.u.tcp.port = htons(port);
+       exp->tuple.dst.protonum = IPPROTO_TCP;
+       exp->mask.src.ip = 0xFFFFFFFF;
+       exp->mask.src.u.tcp.port = 0;
+       exp->mask.dst.ip = 0xFFFFFFFF;
+       exp->mask.dst.u.tcp.port = 0xFFFF;
+       exp->mask.dst.protonum = 0xFF;
+       exp->flags = 0;
+
+       if (ct->tuplehash[dir].tuple.src.ip !=
+           ct->tuplehash[!dir].tuple.dst.ip && nat_h245_hook) {
+               /* NAT needed */
+               ret = nat_h245_hook(pskb, ct, ctinfo, data, dataoff, addr,
+                                   port, exp);
+       } else {                /* Conntrack only */
+               exp->expectfn = ip_conntrack_h245_expect;
+
+               if (ip_conntrack_expect_related(exp) == 0) {
+                       DEBUGP("ip_ct_q931: expect H.245 "
+                              "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                              NIPQUAD(exp->tuple.src.ip),
+                              ntohs(exp->tuple.src.u.tcp.port),
+                              NIPQUAD(exp->tuple.dst.ip),
+                              ntohs(exp->tuple.dst.u.tcp.port));
+               } else
+                       ret = -1;
+       }
+
+       ip_conntrack_expect_put(exp);
+
+       return ret;
+}
+
+/****************************************************************************/
+static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
+                        enum ip_conntrack_info ctinfo,
+                        unsigned char **data, int dataoff,
+                        Setup_UUIE * setup)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       int ret;
+       int i;
+       u_int32_t ip;
+       u_int16_t port;
+
+       DEBUGP("ip_ct_q931: Setup\n");
+
+       if (setup->options & eSetup_UUIE_h245Address) {
+               ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+                                 &setup->h245Address);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if ((setup->options & eSetup_UUIE_destCallSignalAddress) &&
+           (set_h225_addr_hook) &&
+           get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) &&
+           ip != ct->tuplehash[!dir].tuple.src.ip) {
+               DEBUGP("ip_ct_q931: set destCallSignalAddress "
+                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                      NIPQUAD(ip), port,
+                      NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
+                      ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port));
+               ret = set_h225_addr_hook(pskb, data, dataoff,
+                                        &setup->destCallSignalAddress,
+                                        ct->tuplehash[!dir].tuple.src.ip,
+                                        ntohs(ct->tuplehash[!dir].tuple.src.
+                                              u.tcp.port));
+               if (ret < 0)
+                       return -1;
+       }
+
+       if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) &&
+           (set_h225_addr_hook) &&
+           get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port)
+           && ip != ct->tuplehash[!dir].tuple.dst.ip) {
+               DEBUGP("ip_ct_q931: set sourceCallSignalAddress "
+                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                      NIPQUAD(ip), port,
+                      NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
+                      ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port));
+               ret = set_h225_addr_hook(pskb, data, dataoff,
+                                        &setup->sourceCallSignalAddress,
+                                        ct->tuplehash[!dir].tuple.dst.ip,
+                                        ntohs(ct->tuplehash[!dir].tuple.dst.
+                                              u.tcp.port));
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (setup->options & eSetup_UUIE_fastStart) {
+               for (i = 0; i < setup->fastStart.count; i++) {
+                       ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+                                         &setup->fastStart.item[i]);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_callproceeding(struct sk_buff **pskb,
+                                 struct ip_conntrack *ct,
+                                 enum ip_conntrack_info ctinfo,
+                                 unsigned char **data, int dataoff,
+                                 CallProceeding_UUIE * callproc)
+{
+       int ret;
+       int i;
+
+       DEBUGP("ip_ct_q931: CallProceeding\n");
+
+       if (callproc->options & eCallProceeding_UUIE_h245Address) {
+               ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+                                 &callproc->h245Address);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (callproc->options & eCallProceeding_UUIE_fastStart) {
+               for (i = 0; i < callproc->fastStart.count; i++) {
+                       ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+                                         &callproc->fastStart.item[i]);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_connect(struct sk_buff **pskb, struct ip_conntrack *ct,
+                          enum ip_conntrack_info ctinfo,
+                          unsigned char **data, int dataoff,
+                          Connect_UUIE * connect)
+{
+       int ret;
+       int i;
+
+       DEBUGP("ip_ct_q931: Connect\n");
+
+       if (connect->options & eConnect_UUIE_h245Address) {
+               ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+                                 &connect->h245Address);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (connect->options & eConnect_UUIE_fastStart) {
+               for (i = 0; i < connect->fastStart.count; i++) {
+                       ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+                                         &connect->fastStart.item[i]);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_alerting(struct sk_buff **pskb, struct ip_conntrack *ct,
+                           enum ip_conntrack_info ctinfo,
+                           unsigned char **data, int dataoff,
+                           Alerting_UUIE * alert)
+{
+       int ret;
+       int i;
+
+       DEBUGP("ip_ct_q931: Alerting\n");
+
+       if (alert->options & eAlerting_UUIE_h245Address) {
+               ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+                                 &alert->h245Address);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (alert->options & eAlerting_UUIE_fastStart) {
+               for (i = 0; i < alert->fastStart.count; i++) {
+                       ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+                                         &alert->fastStart.item[i]);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_information(struct sk_buff **pskb,
+                              struct ip_conntrack *ct,
+                              enum ip_conntrack_info ctinfo,
+                              unsigned char **data, int dataoff,
+                              Information_UUIE * info)
+{
+       int ret;
+       int i;
+
+       DEBUGP("ip_ct_q931: Information\n");
+
+       if (info->options & eInformation_UUIE_fastStart) {
+               for (i = 0; i < info->fastStart.count; i++) {
+                       ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+                                         &info->fastStart.item[i]);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_facility(struct sk_buff **pskb, struct ip_conntrack *ct,
+                           enum ip_conntrack_info ctinfo,
+                           unsigned char **data, int dataoff,
+                           Facility_UUIE * facility)
+{
+       int ret;
+       int i;
+
+       DEBUGP("ip_ct_q931: Facility\n");
+
+       if (facility->options & eFacility_UUIE_h245Address) {
+               ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+                                 &facility->h245Address);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (facility->options & eFacility_UUIE_fastStart) {
+               for (i = 0; i < facility->fastStart.count; i++) {
+                       ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+                                         &facility->fastStart.item[i]);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_progress(struct sk_buff **pskb, struct ip_conntrack *ct,
+                           enum ip_conntrack_info ctinfo,
+                           unsigned char **data, int dataoff,
+                           Progress_UUIE * progress)
+{
+       int ret;
+       int i;
+
+       DEBUGP("ip_ct_q931: Progress\n");
+
+       if (progress->options & eProgress_UUIE_h245Address) {
+               ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
+                                 &progress->h245Address);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (progress->options & eProgress_UUIE_fastStart) {
+               for (i = 0; i < progress->fastStart.count; i++) {
+                       ret = process_olc(pskb, ct, ctinfo, data, dataoff,
+                                         &progress->fastStart.item[i]);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
+                       enum ip_conntrack_info ctinfo,
+                       unsigned char **data, int dataoff, Q931 * q931)
+{
+       H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu;
+       int i;
+       int ret = 0;
+
+       switch (pdu->h323_message_body.choice) {
+       case eH323_UU_PDU_h323_message_body_setup:
+               ret = process_setup(pskb, ct, ctinfo, data, dataoff,
+                                   &pdu->h323_message_body.setup);
+               break;
+       case eH323_UU_PDU_h323_message_body_callProceeding:
+               ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff,
+                                            &pdu->h323_message_body.
+                                            callProceeding);
+               break;
+       case eH323_UU_PDU_h323_message_body_connect:
+               ret = process_connect(pskb, ct, ctinfo, data, dataoff,
+                                     &pdu->h323_message_body.connect);
+               break;
+       case eH323_UU_PDU_h323_message_body_alerting:
+               ret = process_alerting(pskb, ct, ctinfo, data, dataoff,
+                                      &pdu->h323_message_body.alerting);
+               break;
+       case eH323_UU_PDU_h323_message_body_information:
+               ret = process_information(pskb, ct, ctinfo, data, dataoff,
+                                         &pdu->h323_message_body.
+                                         information);
+               break;
+       case eH323_UU_PDU_h323_message_body_facility:
+               ret = process_facility(pskb, ct, ctinfo, data, dataoff,
+                                      &pdu->h323_message_body.facility);
+               break;
+       case eH323_UU_PDU_h323_message_body_progress:
+               ret = process_progress(pskb, ct, ctinfo, data, dataoff,
+                                      &pdu->h323_message_body.progress);
+               break;
+       default:
+               DEBUGP("ip_ct_q931: Q.931 signal %d\n",
+                      pdu->h323_message_body.choice);
+               break;
+       }
+
+       if (ret < 0)
+               return -1;
+
+       if (pdu->options & eH323_UU_PDU_h245Control) {
+               for (i = 0; i < pdu->h245Control.count; i++) {
+                       ret = process_h245(pskb, ct, ctinfo, data, dataoff,
+                                          &pdu->h245Control.item[i]);
+                       if (ret < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int q931_help(struct sk_buff **pskb, struct ip_conntrack *ct,
+                    enum ip_conntrack_info ctinfo)
+{
+       static Q931 q931;
+       unsigned char *data = NULL;
+       int datalen;
+       int dataoff;
+       int ret;
+
+       /* Until there's been traffic both ways, don't look in packets. */
+       if (ctinfo != IP_CT_ESTABLISHED
+           && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
+               return NF_ACCEPT;
+       }
+       DEBUGP("ip_ct_q931: skblen = %u\n", (*pskb)->len);
+
+       spin_lock_bh(&ip_h323_lock);
+
+       /* Process each TPKT */
+       while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) {
+               DEBUGP("ip_ct_q931: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
+                      NIPQUAD((*pskb)->nh.iph->saddr),
+                      NIPQUAD((*pskb)->nh.iph->daddr), datalen);
+
+               /* Decode Q.931 signal */
+               ret = DecodeQ931(data, datalen, &q931);
+               if (ret < 0) {
+                       if (net_ratelimit())
+                               printk("ip_ct_q931: decoding error: %s\n",
+                                      ret == H323_ERROR_BOUND ?
+                                      "out of bound" : "out of range");
+                       /* We don't drop when decoding error */
+                       break;
+               }
+
+               /* Process Q.931 signal */
+               if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0)
+                       goto drop;
+       }
+
+       spin_unlock_bh(&ip_h323_lock);
+       return NF_ACCEPT;
+
+      drop:
+       spin_unlock_bh(&ip_h323_lock);
+       if (net_ratelimit())
+               printk("ip_ct_q931: packet dropped\n");
+       return NF_DROP;
+}
+
+/****************************************************************************/
+static struct ip_conntrack_helper ip_conntrack_helper_q931 = {
+       .name = "Q.931",
+       .me = THIS_MODULE,
+       .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ ,
+       .timeout = 240,
+       .tuple = {.src = {.u = {__constant_htons(Q931_PORT)}},
+                 .dst = {.protonum = IPPROTO_TCP}},
+       .mask = {.src = {.u = {0xFFFF}},
+                .dst = {.protonum = 0xFF}},
+       .help = q931_help
+};
+
+/****************************************************************************/
+void ip_conntrack_q931_expect(struct ip_conntrack *new,
+                             struct ip_conntrack_expect *this)
+{
+       write_lock_bh(&ip_conntrack_lock);
+       new->helper = &ip_conntrack_helper_q931;
+       write_unlock_bh(&ip_conntrack_lock);
+}
+
+/****************************************************************************/
+static unsigned char *get_udp_data(struct sk_buff **pskb, int *datalen)
+{
+       struct udphdr _uh, *uh;
+       int dataoff;
+
+       uh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, sizeof(_uh),
+                               &_uh);
+       if (uh == NULL)
+               return NULL;
+       dataoff = (*pskb)->nh.iph->ihl * 4 + sizeof(_uh);
+       if (dataoff >= (*pskb)->len)
+               return NULL;
+       *datalen = (*pskb)->len - dataoff;
+       return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer);
+}
+
+/****************************************************************************/
+static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct,
+                                              u_int32_t ip, u_int16_t port)
+{
+       struct ip_conntrack_expect *exp;
+       struct ip_conntrack_tuple tuple;
+
+       tuple.src.ip = 0;
+       tuple.src.u.tcp.port = 0;
+       tuple.dst.ip = ip;
+       tuple.dst.u.tcp.port = htons(port);
+       tuple.dst.protonum = IPPROTO_TCP;
+
+       exp = __ip_conntrack_expect_find(&tuple);
+       if (exp->master == ct)
+               return exp;
+       return NULL;
+}
+
+/****************************************************************************/
+static int set_expect_timeout(struct ip_conntrack_expect *exp,
+                             unsigned timeout)
+{
+       if (!exp || !del_timer(&exp->timeout))
+               return 0;
+
+       exp->timeout.expires = jiffies + timeout * HZ;
+       add_timer(&exp->timeout);
+
+       return 1;
+}
+
+/****************************************************************************/
+static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data,
+                      TransportAddress * addr, int count)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       int ret = 0;
+       int i;
+       u_int32_t ip;
+       u_int16_t port;
+       struct ip_conntrack_expect *exp;
+
+       /* Look for the first related address */
+       for (i = 0; i < count; i++) {
+               if (get_h225_addr(*data, &addr[i], &ip, &port) &&
+                   ip == ct->tuplehash[dir].tuple.src.ip && port != 0)
+                       break;
+       }
+
+       if (i >= count)         /* Not found */
+               return 0;
+
+       /* Create expect for Q.931 */
+       if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+               return -1;
+       exp->tuple.src.ip = gkrouted_only ?     /* only accept calls from GK? */
+           ct->tuplehash[!dir].tuple.src.ip : 0;
+       exp->tuple.src.u.tcp.port = 0;
+       exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
+       exp->tuple.dst.u.tcp.port = htons(port);
+       exp->tuple.dst.protonum = IPPROTO_TCP;
+       exp->mask.src.ip = gkrouted_only ? 0xFFFFFFFF : 0;
+       exp->mask.src.u.tcp.port = 0;
+       exp->mask.dst.ip = 0xFFFFFFFF;
+       exp->mask.dst.u.tcp.port = 0xFFFF;
+       exp->mask.dst.protonum = 0xFF;
+       exp->flags = IP_CT_EXPECT_PERMANENT;    /* Accept multiple calls */
+
+       if (nat_q931_hook) {    /* Need NAT */
+               ret = nat_q931_hook(pskb, ct, ctinfo, data, addr, i,
+                                   port, exp);
+       } else {                /* Conntrack only */
+               exp->expectfn = ip_conntrack_q931_expect;
+
+               if (ip_conntrack_expect_related(exp) == 0) {
+                       DEBUGP("ip_ct_ras: expect Q.931 "
+                              "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                              NIPQUAD(exp->tuple.src.ip),
+                              ntohs(exp->tuple.src.u.tcp.port),
+                              NIPQUAD(exp->tuple.dst.ip),
+                              ntohs(exp->tuple.dst.u.tcp.port));
+
+                       /* Save port for looking up expect in processing RCF */
+                       info->sig_port[dir] = port;
+               } else
+                       ret = -1;
+       }
+
+       ip_conntrack_expect_put(exp);
+
+       return ret;
+}
+
+/****************************************************************************/
+static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, GatekeeperRequest * grq)
+{
+       DEBUGP("ip_ct_ras: GRQ\n");
+
+       if (set_ras_addr_hook)  /* NATed */
+               return set_ras_addr_hook(pskb, ct, ctinfo, data,
+                                        &grq->rasAddress, 1);
+       return 0;
+}
+
+/* Declare before using */
+static void ip_conntrack_ras_expect(struct ip_conntrack *new,
+                                   struct ip_conntrack_expect *this);
+
+/****************************************************************************/
+static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, GatekeeperConfirm * gcf)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       int ret = 0;
+       u_int32_t ip;
+       u_int16_t port;
+       struct ip_conntrack_expect *exp;
+
+       DEBUGP("ip_ct_ras: GCF\n");
+
+       if (!get_h225_addr(*data, &gcf->rasAddress, &ip, &port))
+               return 0;
+
+       /* Registration port is the same as discovery port */
+       if (ip == ct->tuplehash[dir].tuple.src.ip &&
+           port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port))
+               return 0;
+
+       /* Avoid RAS expectation loops. A GCF is never expected. */
+       if (test_bit(IPS_EXPECTED_BIT, &ct->status))
+               return 0;
+
+       /* Need new expect */
+       if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+               return -1;
+       exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+       exp->tuple.src.u.tcp.port = 0;
+       exp->tuple.dst.ip = ip;
+       exp->tuple.dst.u.tcp.port = htons(port);
+       exp->tuple.dst.protonum = IPPROTO_UDP;
+       exp->mask.src.ip = 0xFFFFFFFF;
+       exp->mask.src.u.tcp.port = 0;
+       exp->mask.dst.ip = 0xFFFFFFFF;
+       exp->mask.dst.u.tcp.port = 0xFFFF;
+       exp->mask.dst.protonum = 0xFF;
+       exp->flags = 0;
+       exp->expectfn = ip_conntrack_ras_expect;
+       if (ip_conntrack_expect_related(exp) == 0) {
+               DEBUGP("ip_ct_ras: expect RAS "
+                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                      NIPQUAD(exp->tuple.src.ip),
+                      ntohs(exp->tuple.src.u.tcp.port),
+                      NIPQUAD(exp->tuple.dst.ip),
+                      ntohs(exp->tuple.dst.u.tcp.port));
+       } else
+               ret = -1;
+
+       ip_conntrack_expect_put(exp);
+
+       return ret;
+}
+
+/****************************************************************************/
+static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, RegistrationRequest * rrq)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int ret;
+
+       DEBUGP("ip_ct_ras: RRQ\n");
+
+       ret = expect_q931(pskb, ct, ctinfo, data,
+                         rrq->callSignalAddress.item,
+                         rrq->callSignalAddress.count);
+       if (ret < 0)
+               return -1;
+
+       if (set_ras_addr_hook) {
+               ret = set_ras_addr_hook(pskb, ct, ctinfo, data,
+                                       rrq->rasAddress.item,
+                                       rrq->rasAddress.count);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (rrq->options & eRegistrationRequest_timeToLive) {
+               DEBUGP("ip_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive);
+               info->timeout = rrq->timeToLive;
+       } else
+               info->timeout = 0;
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, RegistrationConfirm * rcf)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       int ret;
+       struct ip_conntrack_expect *exp;
+
+       DEBUGP("ip_ct_ras: RCF\n");
+
+       if (set_sig_addr_hook) {
+               ret = set_sig_addr_hook(pskb, ct, ctinfo, data,
+                                       rcf->callSignalAddress.item,
+                                       rcf->callSignalAddress.count);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (rcf->options & eRegistrationConfirm_timeToLive) {
+               DEBUGP("ip_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive);
+               info->timeout = rcf->timeToLive;
+       }
+
+       if (info->timeout > 0) {
+               DEBUGP
+                   ("ip_ct_ras: set RAS connection timeout to %u seconds\n",
+                    info->timeout);
+               ip_ct_refresh_acct(ct, ctinfo, NULL, info->timeout * HZ);
+
+               /* Set expect timeout */
+               read_lock_bh(&ip_conntrack_lock);
+               exp = find_expect(ct, ct->tuplehash[dir].tuple.dst.ip,
+                                 info->sig_port[!dir]);
+               if (exp) {
+                       DEBUGP("ip_ct_ras: set Q.931 expect "
+                              "(%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu) "
+                              "timeout to %u seconds\n",
+                              NIPQUAD(exp->tuple.src.ip),
+                              ntohs(exp->tuple.src.u.tcp.port),
+                              NIPQUAD(exp->tuple.dst.ip),
+                              ntohs(exp->tuple.dst.u.tcp.port),
+                              info->timeout);
+                       set_expect_timeout(exp, info->timeout);
+               }
+               read_unlock_bh(&ip_conntrack_lock);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, UnregistrationRequest * urq)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       int ret;
+
+       DEBUGP("ip_ct_ras: URQ\n");
+
+       if (set_sig_addr_hook) {
+               ret = set_sig_addr_hook(pskb, ct, ctinfo, data,
+                                       urq->callSignalAddress.item,
+                                       urq->callSignalAddress.count);
+               if (ret < 0)
+                       return -1;
+       }
+
+       /* Clear old expect */
+       ip_ct_remove_expectations(ct);
+       info->sig_port[dir] = 0;
+       info->sig_port[!dir] = 0;
+
+       /* Give it 30 seconds for UCF or URJ */
+       ip_ct_refresh_acct(ct, ctinfo, NULL, 30 * HZ);
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, AdmissionRequest * arq)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       u_int32_t ip;
+       u_int16_t port;
+
+       DEBUGP("ip_ct_ras: ARQ\n");
+
+       if ((arq->options & eAdmissionRequest_destCallSignalAddress) &&
+           get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) &&
+           ip == ct->tuplehash[dir].tuple.src.ip &&
+           port == info->sig_port[dir] && set_h225_addr_hook) {
+               /* Answering ARQ */
+               return set_h225_addr_hook(pskb, data, 0,
+                                         &arq->destCallSignalAddress,
+                                         ct->tuplehash[!dir].tuple.dst.ip,
+                                         info->sig_port[!dir]);
+       }
+
+       if ((arq->options & eAdmissionRequest_srcCallSignalAddress) &&
+           get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) &&
+           ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr_hook) {
+               /* Calling ARQ */
+               return set_h225_addr_hook(pskb, data, 0,
+                                         &arq->srcCallSignalAddress,
+                                         ct->tuplehash[!dir].tuple.dst.ip,
+                                         port);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, AdmissionConfirm * acf)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       int ret = 0;
+       u_int32_t ip;
+       u_int16_t port;
+       struct ip_conntrack_expect *exp;
+
+       DEBUGP("ip_ct_ras: ACF\n");
+
+       if (!get_h225_addr(*data, &acf->destCallSignalAddress, &ip, &port))
+               return 0;
+
+       if (ip == ct->tuplehash[dir].tuple.dst.ip) {    /* Answering ACF */
+               if (set_sig_addr_hook)
+                       return set_sig_addr_hook(pskb, ct, ctinfo, data,
+                                                &acf->destCallSignalAddress,
+                                                1);
+               return 0;
+       }
+
+       /* Need new expect */
+       if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+               return -1;
+       exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+       exp->tuple.src.u.tcp.port = 0;
+       exp->tuple.dst.ip = ip;
+       exp->tuple.dst.u.tcp.port = htons(port);
+       exp->tuple.dst.protonum = IPPROTO_TCP;
+       exp->mask.src.ip = 0xFFFFFFFF;
+       exp->mask.src.u.tcp.port = 0;
+       exp->mask.dst.ip = 0xFFFFFFFF;
+       exp->mask.dst.u.tcp.port = 0xFFFF;
+       exp->mask.dst.protonum = 0xFF;
+       exp->flags = IP_CT_EXPECT_PERMANENT;
+       exp->expectfn = ip_conntrack_q931_expect;
+
+       if (ip_conntrack_expect_related(exp) == 0) {
+               DEBUGP("ip_ct_ras: expect Q.931 "
+                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                      NIPQUAD(exp->tuple.src.ip),
+                      ntohs(exp->tuple.src.u.tcp.port),
+                      NIPQUAD(exp->tuple.dst.ip),
+                      ntohs(exp->tuple.dst.u.tcp.port));
+       } else
+               ret = -1;
+
+       ip_conntrack_expect_put(exp);
+
+       return ret;
+}
+
+/****************************************************************************/
+static int process_lrq(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, LocationRequest * lrq)
+{
+       DEBUGP("ip_ct_ras: LRQ\n");
+
+       if (set_ras_addr_hook)
+               return set_ras_addr_hook(pskb, ct, ctinfo, data,
+                                        &lrq->replyAddress, 1);
+       return 0;
+}
+
+/****************************************************************************/
+static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, LocationConfirm * lcf)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       int ret = 0;
+       u_int32_t ip;
+       u_int16_t port;
+       struct ip_conntrack_expect *exp = NULL;
+
+       DEBUGP("ip_ct_ras: LCF\n");
+
+       if (!get_h225_addr(*data, &lcf->callSignalAddress, &ip, &port))
+               return 0;
+
+       /* Need new expect for call signal */
+       if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
+               return -1;
+       exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
+       exp->tuple.src.u.tcp.port = 0;
+       exp->tuple.dst.ip = ip;
+       exp->tuple.dst.u.tcp.port = htons(port);
+       exp->tuple.dst.protonum = IPPROTO_TCP;
+       exp->mask.src.ip = 0xFFFFFFFF;
+       exp->mask.src.u.tcp.port = 0;
+       exp->mask.dst.ip = 0xFFFFFFFF;
+       exp->mask.dst.u.tcp.port = 0xFFFF;
+       exp->mask.dst.protonum = 0xFF;
+       exp->flags = IP_CT_EXPECT_PERMANENT;
+       exp->expectfn = ip_conntrack_q931_expect;
+
+       if (ip_conntrack_expect_related(exp) == 0) {
+               DEBUGP("ip_ct_ras: expect Q.931 "
+                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                      NIPQUAD(exp->tuple.src.ip),
+                      ntohs(exp->tuple.src.u.tcp.port),
+                      NIPQUAD(exp->tuple.dst.ip),
+                      ntohs(exp->tuple.dst.u.tcp.port));
+       } else
+               ret = -1;
+
+       ip_conntrack_expect_put(exp);
+
+       /* Ignore rasAddress */
+
+       return ret;
+}
+
+/****************************************************************************/
+static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, InfoRequestResponse * irr)
+{
+       int ret;
+
+       DEBUGP("ip_ct_ras: IRR\n");
+
+       if (set_ras_addr_hook) {
+               ret = set_ras_addr_hook(pskb, ct, ctinfo, data,
+                                       &irr->rasAddress, 1);
+               if (ret < 0)
+                       return -1;
+       }
+
+       if (set_sig_addr_hook) {
+               ret = set_sig_addr_hook(pskb, ct, ctinfo, data,
+                                       irr->callSignalAddress.item,
+                                       irr->callSignalAddress.count);
+               if (ret < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int process_ras(struct sk_buff **pskb, struct ip_conntrack *ct,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned char **data, RasMessage * ras)
+{
+       switch (ras->choice) {
+       case eRasMessage_gatekeeperRequest:
+               return process_grq(pskb, ct, ctinfo, data,
+                                  &ras->gatekeeperRequest);
+       case eRasMessage_gatekeeperConfirm:
+               return process_gcf(pskb, ct, ctinfo, data,
+                                  &ras->gatekeeperConfirm);
+       case eRasMessage_registrationRequest:
+               return process_rrq(pskb, ct, ctinfo, data,
+                                  &ras->registrationRequest);
+       case eRasMessage_registrationConfirm:
+               return process_rcf(pskb, ct, ctinfo, data,
+                                  &ras->registrationConfirm);
+       case eRasMessage_unregistrationRequest:
+               return process_urq(pskb, ct, ctinfo, data,
+                                  &ras->unregistrationRequest);
+       case eRasMessage_admissionRequest:
+               return process_arq(pskb, ct, ctinfo, data,
+                                  &ras->admissionRequest);
+       case eRasMessage_admissionConfirm:
+               return process_acf(pskb, ct, ctinfo, data,
+                                  &ras->admissionConfirm);
+       case eRasMessage_locationRequest:
+               return process_lrq(pskb, ct, ctinfo, data,
+                                  &ras->locationRequest);
+       case eRasMessage_locationConfirm:
+               return process_lcf(pskb, ct, ctinfo, data,
+                                  &ras->locationConfirm);
+       case eRasMessage_infoRequestResponse:
+               return process_irr(pskb, ct, ctinfo, data,
+                                  &ras->infoRequestResponse);
+       default:
+               DEBUGP("ip_ct_ras: RAS message %d\n", ras->choice);
+               break;
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int ras_help(struct sk_buff **pskb, struct ip_conntrack *ct,
+                   enum ip_conntrack_info ctinfo)
+{
+       static RasMessage ras;
+       unsigned char *data;
+       int datalen = 0;
+       int ret;
+
+       DEBUGP("ip_ct_ras: skblen = %u\n", (*pskb)->len);
+
+       spin_lock_bh(&ip_h323_lock);
+
+       /* Get UDP data */
+       data = get_udp_data(pskb, &datalen);
+       if (data == NULL)
+               goto accept;
+       DEBUGP("ip_ct_ras: RAS message %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
+              NIPQUAD((*pskb)->nh.iph->saddr),
+              NIPQUAD((*pskb)->nh.iph->daddr), datalen);
+
+       /* Decode RAS message */
+       ret = DecodeRasMessage(data, datalen, &ras);
+       if (ret < 0) {
+               if (net_ratelimit())
+                       printk("ip_ct_ras: decoding error: %s\n",
+                              ret == H323_ERROR_BOUND ?
+                              "out of bound" : "out of range");
+               goto accept;
+       }
+
+       /* Process RAS message */
+       if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0)
+               goto drop;
+
+      accept:
+       spin_unlock_bh(&ip_h323_lock);
+       return NF_ACCEPT;
+
+      drop:
+       spin_unlock_bh(&ip_h323_lock);
+       if (net_ratelimit())
+               printk("ip_ct_ras: packet dropped\n");
+       return NF_DROP;
+}
+
+/****************************************************************************/
+static struct ip_conntrack_helper ip_conntrack_helper_ras = {
+       .name = "RAS",
+       .me = THIS_MODULE,
+       .max_expected = 32,
+       .timeout = 240,
+       .tuple = {.src = {.u = {__constant_htons(RAS_PORT)}},
+                 .dst = {.protonum = IPPROTO_UDP}},
+       .mask = {.src = {.u = {0xFFFE}},
+                .dst = {.protonum = 0xFF}},
+       .help = ras_help,
+};
+
+/****************************************************************************/
+static void ip_conntrack_ras_expect(struct ip_conntrack *new,
+                                   struct ip_conntrack_expect *this)
+{
+       write_lock_bh(&ip_conntrack_lock);
+       new->helper = &ip_conntrack_helper_ras;
+       write_unlock_bh(&ip_conntrack_lock);
+}
+
+/****************************************************************************/
+/* Not __exit - called from init() */
+static void fini(void)
+{
+       ip_conntrack_helper_unregister(&ip_conntrack_helper_ras);
+       ip_conntrack_helper_unregister(&ip_conntrack_helper_q931);
+       kfree(h323_buffer);
+       DEBUGP("ip_ct_h323: fini\n");
+}
+
+/****************************************************************************/
+static int __init init(void)
+{
+       int ret;
+
+       h323_buffer = kmalloc(65536, GFP_KERNEL);
+       if (!h323_buffer)
+               return -ENOMEM;
+       if ((ret = ip_conntrack_helper_register(&ip_conntrack_helper_q931)) ||
+           (ret = ip_conntrack_helper_register(&ip_conntrack_helper_ras))) {
+               fini();
+               return ret;
+       }
+
+       DEBUGP("ip_ct_h323: init success\n");
+       return 0;
+}
+
+/****************************************************************************/
+module_init(init);
+module_exit(fini);
+
+EXPORT_SYMBOL(get_h245_addr);
+EXPORT_SYMBOL(get_h225_addr);
+EXPORT_SYMBOL(ip_conntrack_h245_expect);
+EXPORT_SYMBOL(ip_conntrack_q931_expect);
+EXPORT_SYMBOL(set_h245_addr_hook);
+EXPORT_SYMBOL(set_h225_addr_hook);
+EXPORT_SYMBOL(set_sig_addr_hook);
+EXPORT_SYMBOL(set_ras_addr_hook);
+EXPORT_SYMBOL(nat_rtp_rtcp_hook);
+EXPORT_SYMBOL(nat_t120_hook);
+EXPORT_SYMBOL(nat_h245_hook);
+EXPORT_SYMBOL(nat_q931_hook);
+
+MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
+MODULE_DESCRIPTION("H.323 connection tracking helper");
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
new file mode 100644 (file)
index 0000000..afa5251
--- /dev/null
@@ -0,0 +1,870 @@
+/****************************************************************************
+ * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323
+ *                                  conntrack/NAT module.
+ *
+ * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@hotmail.com>
+ *
+ * This source code is licensed under General Public License version 2.
+ *
+ * See ip_conntrack_helper_h323_asn1.h for details.
+ *
+ ****************************************************************************/
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#else
+#include <stdio.h>
+#endif
+#include "ip_conntrack_helper_h323_asn1.h"
+
+/* Trace Flag */
+#ifndef H323_TRACE
+#define H323_TRACE 0
+#endif
+
+#if H323_TRACE
+#define TAB_SIZE 4
+#define IFTHEN(cond, act) if(cond){act;}
+#ifdef __KERNEL__
+#define PRINT printk
+#else
+#define PRINT printf
+#endif
+#define FNAME(name) name,
+#else
+#define IFTHEN(cond, act)
+#define PRINT(fmt, args...)
+#define FNAME(name)
+#endif
+
+/* ASN.1 Types */
+#define NUL 0
+#define BOOL 1
+#define OID 2
+#define INT 3
+#define ENUM 4
+#define BITSTR 5
+#define NUMSTR 6
+#define NUMDGT 6
+#define TBCDSTR 6
+#define OCTSTR 7
+#define PRTSTR 7
+#define IA5STR 7
+#define GENSTR 7
+#define BMPSTR 8
+#define SEQ 9
+#define SET 9
+#define SEQOF 10
+#define SETOF 10
+#define CHOICE 11
+
+/* Constraint Types */
+#define FIXD 0
+/* #define BITS 1-8 */
+#define BYTE 9
+#define WORD 10
+#define CONS 11
+#define SEMI 12
+#define UNCO 13
+
+/* ASN.1 Type Attributes */
+#define SKIP 0
+#define STOP 1
+#define DECODE 2
+#define EXT 4
+#define OPEN 8
+#define OPT 16
+
+
+/* ASN.1 Field Structure */
+typedef struct field_t {
+#if H323_TRACE
+       char *name;
+#endif
+       unsigned char type;
+       unsigned char sz;
+       unsigned char lb;
+       unsigned char ub;
+       unsigned short attr;
+       unsigned short offset;
+       struct field_t *fields;
+} field_t;
+
+/* Bit Stream */
+typedef struct {
+       unsigned char *buf;
+       unsigned char *beg;
+       unsigned char *end;
+       unsigned char *cur;
+       unsigned bit;
+} bitstr_t;
+
+/* Tool Functions */
+#define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;}
+#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;}
+#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;}
+#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND)
+static unsigned get_len(bitstr_t * bs);
+static unsigned get_bit(bitstr_t * bs);
+static unsigned get_bits(bitstr_t * bs, unsigned b);
+static unsigned get_bitmap(bitstr_t * bs, unsigned b);
+static unsigned get_uint(bitstr_t * bs, int b);
+
+/* Decoder Functions */
+static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_int(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level);
+
+/* Decoder Functions Vector */
+typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int);
+static decoder_t Decoders[] = {
+       decode_nul,
+       decode_bool,
+       decode_oid,
+       decode_int,
+       decode_enum,
+       decode_bitstr,
+       decode_numstr,
+       decode_octstr,
+       decode_bmpstr,
+       decode_seq,
+       decode_seqof,
+       decode_choice,
+};
+
+/****************************************************************************
+ * H.323 Types
+ ****************************************************************************/
+#include "ip_conntrack_helper_h323_types.c"
+
+/****************************************************************************
+ * Functions
+ ****************************************************************************/
+/* Assume bs is aligned && v < 16384 */
+unsigned get_len(bitstr_t * bs)
+{
+       unsigned v;
+
+       v = *bs->cur++;
+
+       if (v & 0x80) {
+               v &= 0x3f;
+               v <<= 8;
+               v += *bs->cur++;
+       }
+
+       return v;
+}
+
+/****************************************************************************/
+unsigned get_bit(bitstr_t * bs)
+{
+       unsigned b = (*bs->cur) & (0x80 >> bs->bit);
+
+       INC_BIT(bs);
+
+       return b;
+}
+
+/****************************************************************************/
+/* Assume b <= 8 */
+unsigned get_bits(bitstr_t * bs, unsigned b)
+{
+       unsigned v, l;
+
+       v = (*bs->cur) & (0xffU >> bs->bit);
+       l = b + bs->bit;
+
+       if (l < 8) {
+               v >>= 8 - l;
+               bs->bit = l;
+       } else if (l == 8) {
+               bs->cur++;
+               bs->bit = 0;
+       } else {                /* l > 8 */
+
+               v <<= 8;
+               v += *(++bs->cur);
+               v >>= 16 - l;
+               bs->bit = l - 8;
+       }
+
+       return v;
+}
+
+/****************************************************************************/
+/* Assume b <= 32 */
+unsigned get_bitmap(bitstr_t * bs, unsigned b)
+{
+       unsigned v, l, shift, bytes;
+
+       if (!b)
+               return 0;
+
+       l = bs->bit + b;
+
+       if (l < 8) {
+               v = (unsigned) (*bs->cur) << (bs->bit + 24);
+               bs->bit = l;
+       } else if (l == 8) {
+               v = (unsigned) (*bs->cur++) << (bs->bit + 24);
+               bs->bit = 0;
+       } else {
+               for (bytes = l >> 3, shift = 24, v = 0; bytes;
+                    bytes--, shift -= 8)
+                       v |= (unsigned) (*bs->cur++) << shift;
+
+               if (l < 32) {
+                       v |= (unsigned) (*bs->cur) << shift;
+                       v <<= bs->bit;
+               } else if (l > 32) {
+                       v <<= bs->bit;
+                       v |= (*bs->cur) >> (8 - bs->bit);
+               }
+
+               bs->bit = l & 0x7;
+       }
+
+       v &= 0xffffffff << (32 - b);
+
+       return v;
+}
+
+/****************************************************************************
+ * Assume bs is aligned and sizeof(unsigned int) == 4
+ ****************************************************************************/
+unsigned get_uint(bitstr_t * bs, int b)
+{
+       unsigned v = 0;
+
+       switch (b) {
+       case 4:
+               v |= *bs->cur++;
+               v <<= 8;
+       case 3:
+               v |= *bs->cur++;
+               v <<= 8;
+       case 2:
+               v |= *bs->cur++;
+               v <<= 8;
+       case 1:
+               v |= *bs->cur++;
+               break;
+       }
+       return v;
+}
+
+/****************************************************************************/
+int decode_nul(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_bool(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       INC_BIT(bs);
+
+       CHECK_BOUND(bs, 0);
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_oid(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       int len;
+
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       BYTE_ALIGN(bs);
+       CHECK_BOUND(bs, 1);
+       len = *bs->cur++;
+       bs->cur += len;
+
+       CHECK_BOUND(bs, 0);
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       unsigned len;
+
+       PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
+
+       switch (f->sz) {
+       case BYTE:              /* Range == 256 */
+               BYTE_ALIGN(bs);
+               bs->cur++;
+               break;
+       case WORD:              /* 257 <= Range <= 64K */
+               BYTE_ALIGN(bs);
+               bs->cur += 2;
+               break;
+       case CONS:              /* 64K < Range < 4G */
+               len = get_bits(bs, 2) + 1;
+               BYTE_ALIGN(bs);
+               if (base && (f->attr & DECODE)) {       /* timeToLive */
+                       unsigned v = get_uint(bs, len) + f->lb;
+                       PRINT(" = %u", v);
+                       *((unsigned *) (base + f->offset)) = v;
+               }
+               bs->cur += len;
+               break;
+       case UNCO:
+               BYTE_ALIGN(bs);
+               CHECK_BOUND(bs, 2);
+               len = get_len(bs);
+               bs->cur += len;
+               break;
+       default:                /* 2 <= Range <= 255 */
+               INC_BITS(bs, f->sz);
+               break;
+       }
+
+       PRINT("\n");
+
+       CHECK_BOUND(bs, 0);
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_enum(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       if ((f->attr & EXT) && get_bit(bs)) {
+               INC_BITS(bs, 7);
+       } else {
+               INC_BITS(bs, f->sz);
+       }
+
+       CHECK_BOUND(bs, 0);
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       unsigned len;
+
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       BYTE_ALIGN(bs);
+       switch (f->sz) {
+       case FIXD:              /* fixed length > 16 */
+               len = f->lb;
+               break;
+       case WORD:              /* 2-byte length */
+               CHECK_BOUND(bs, 2);
+               len = (*bs->cur++) << 8;
+               len += (*bs->cur++) + f->lb;
+               break;
+       case SEMI:
+               CHECK_BOUND(bs, 2);
+               len = get_len(bs);
+               break;
+       default:
+               len = 0;
+               break;
+       }
+
+       bs->cur += len >> 3;
+       bs->bit = len & 7;
+
+       CHECK_BOUND(bs, 0);
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       unsigned len;
+
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       /* 2 <= Range <= 255 */
+       len = get_bits(bs, f->sz) + f->lb;
+
+       BYTE_ALIGN(bs);
+       INC_BITS(bs, (len << 2));
+
+       CHECK_BOUND(bs, 0);
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       unsigned len;
+
+       PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
+
+       switch (f->sz) {
+       case FIXD:              /* Range == 1 */
+               if (f->lb > 2) {
+                       BYTE_ALIGN(bs);
+                       if (base && (f->attr & DECODE)) {
+                               /* The IP Address */
+                               IFTHEN(f->lb == 4,
+                                      PRINT(" = %d.%d.%d.%d:%d",
+                                            bs->cur[0], bs->cur[1],
+                                            bs->cur[2], bs->cur[3],
+                                            bs->cur[4] * 256 + bs->cur[5]));
+                               *((unsigned *) (base + f->offset)) =
+                                   bs->cur - bs->buf;
+                       }
+               }
+               len = f->lb;
+               break;
+       case BYTE:              /* Range == 256 */
+               BYTE_ALIGN(bs);
+               CHECK_BOUND(bs, 1);
+               len = (*bs->cur++) + f->lb;
+               break;
+       case SEMI:
+               BYTE_ALIGN(bs);
+               CHECK_BOUND(bs, 2);
+               len = get_len(bs) + f->lb;
+               break;
+       default:                /* 2 <= Range <= 255 */
+               len = get_bits(bs, f->sz) + f->lb;
+               BYTE_ALIGN(bs);
+               break;
+       }
+
+       bs->cur += len;
+
+       PRINT("\n");
+
+       CHECK_BOUND(bs, 0);
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       unsigned len;
+
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       switch (f->sz) {
+       case BYTE:              /* Range == 256 */
+               BYTE_ALIGN(bs);
+               CHECK_BOUND(bs, 1);
+               len = (*bs->cur++) + f->lb;
+               break;
+       default:                /* 2 <= Range <= 255 */
+               len = get_bits(bs, f->sz) + f->lb;
+               BYTE_ALIGN(bs);
+               break;
+       }
+
+       bs->cur += len << 1;
+
+       CHECK_BOUND(bs, 0);
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len;
+       int err;
+       field_t *son;
+       unsigned char *beg = NULL;
+
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       /* Decode? */
+       base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
+
+       /* Extensible? */
+       ext = (f->attr & EXT) ? get_bit(bs) : 0;
+
+       /* Get fields bitmap */
+       bmp = get_bitmap(bs, f->sz);
+       if (base)
+               *(unsigned *) base = bmp;
+
+       /* Decode the root components */
+       for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) {
+               if (son->attr & STOP) {
+                       PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
+                             son->name);
+                       return H323_ERROR_STOP;
+               }
+
+               if (son->attr & OPT) {  /* Optional component */
+                       if (!((0x80000000U >> (opt++)) & bmp))  /* Not exist */
+                               continue;
+               }
+
+               /* Decode */
+               if (son->attr & OPEN) { /* Open field */
+                       CHECK_BOUND(bs, 2);
+                       len = get_len(bs);
+                       CHECK_BOUND(bs, len);
+                       if (!base) {
+                               PRINT("%*.s%s\n", (level + 1) * TAB_SIZE,
+                                     " ", son->name);
+                               bs->cur += len;
+                               continue;
+                       }
+                       beg = bs->cur;
+
+                       /* Decode */
+                       if ((err = (Decoders[son->type]) (bs, son, base,
+                                                         level + 1)) >
+                           H323_ERROR_STOP)
+                               return err;
+
+                       bs->cur = beg + len;
+                       bs->bit = 0;
+               } else if ((err = (Decoders[son->type]) (bs, son, base,
+                                                        level + 1)))
+                       return err;
+       }
+
+       /* No extension? */
+       if (!ext)
+               return H323_ERROR_NONE;
+
+       /* Get the extension bitmap */
+       bmp2_len = get_bits(bs, 7) + 1;
+       CHECK_BOUND(bs, (bmp2_len + 7) >> 3);
+       bmp2 = get_bitmap(bs, bmp2_len);
+       bmp |= bmp2 >> f->sz;
+       if (base)
+               *(unsigned *) base = bmp;
+       BYTE_ALIGN(bs);
+
+       /* Decode the extension components */
+       for (opt = 0; opt < bmp2_len; opt++, i++, son++) {
+               if (son->attr & STOP) {
+                       PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
+                             son->name);
+                       return H323_ERROR_STOP;
+               }
+
+               if (!((0x80000000 >> opt) & bmp2))      /* Not present */
+                       continue;
+
+               /* Check Range */
+               if (i >= f->ub) {       /* Newer Version? */
+                       CHECK_BOUND(bs, 2);
+                       len = get_len(bs);
+                       CHECK_BOUND(bs, len);
+                       bs->cur += len;
+                       continue;
+               }
+
+               CHECK_BOUND(bs, 2);
+               len = get_len(bs);
+               CHECK_BOUND(bs, len);
+               if (!base || !(son->attr & DECODE)) {
+                       PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
+                             son->name);
+                       bs->cur += len;
+                       continue;
+               }
+               beg = bs->cur;
+
+               if ((err = (Decoders[son->type]) (bs, son, base,
+                                                 level + 1)) >
+                   H323_ERROR_STOP)
+                       return err;
+
+               bs->cur = beg + len;
+               bs->bit = 0;
+       }
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       unsigned count, effective_count = 0, i, len = 0;
+       int err;
+       field_t *son;
+       unsigned char *beg = NULL;
+
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       /* Decode? */
+       base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
+
+       /* Decode item count */
+       switch (f->sz) {
+       case BYTE:
+               BYTE_ALIGN(bs);
+               CHECK_BOUND(bs, 1);
+               count = *bs->cur++;
+               break;
+       case WORD:
+               BYTE_ALIGN(bs);
+               CHECK_BOUND(bs, 2);
+               count = *bs->cur++;
+               count <<= 8;
+               count = *bs->cur++;
+               break;
+       case SEMI:
+               BYTE_ALIGN(bs);
+               CHECK_BOUND(bs, 2);
+               count = get_len(bs);
+               break;
+       default:
+               count = get_bits(bs, f->sz);
+               break;
+       }
+       count += f->lb;
+
+       /* Write Count */
+       if (base) {
+               effective_count = count > f->ub ? f->ub : count;
+               *(unsigned *) base = effective_count;
+               base += sizeof(unsigned);
+       }
+
+       /* Decode nested field */
+       son = f->fields;
+       if (base)
+               base -= son->offset;
+       for (i = 0; i < count; i++) {
+               if (son->attr & OPEN) {
+                       BYTE_ALIGN(bs);
+                       len = get_len(bs);
+                       CHECK_BOUND(bs, len);
+                       if (!base || !(son->attr & DECODE)) {
+                               PRINT("%*.s%s\n", (level + 1) * TAB_SIZE,
+                                     " ", son->name);
+                               bs->cur += len;
+                               continue;
+                       }
+                       beg = bs->cur;
+
+                       if ((err = (Decoders[son->type]) (bs, son,
+                                                         i <
+                                                         effective_count ?
+                                                         base : NULL,
+                                                         level + 1)) >
+                           H323_ERROR_STOP)
+                               return err;
+
+                       bs->cur = beg + len;
+                       bs->bit = 0;
+               } else
+                   if ((err = (Decoders[son->type]) (bs, son,
+                                                     i < effective_count ?
+                                                     base : NULL,
+                                                     level + 1)))
+                       return err;
+
+               if (base)
+                       base += son->offset;
+       }
+
+       return H323_ERROR_NONE;
+}
+
+
+/****************************************************************************/
+int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
+{
+       unsigned type, ext, len = 0;
+       int err;
+       field_t *son;
+       unsigned char *beg = NULL;
+
+       PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+
+       /* Decode? */
+       base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
+
+       /* Decode the choice index number */
+       if ((f->attr & EXT) && get_bit(bs)) {
+               ext = 1;
+               type = get_bits(bs, 7) + f->lb;
+       } else {
+               ext = 0;
+               type = get_bits(bs, f->sz);
+       }
+
+       /* Check Range */
+       if (type >= f->ub) {    /* Newer version? */
+               BYTE_ALIGN(bs);
+               len = get_len(bs);
+               CHECK_BOUND(bs, len);
+               bs->cur += len;
+               return H323_ERROR_NONE;
+       }
+
+       /* Write Type */
+       if (base)
+               *(unsigned *) base = type;
+
+       /* Transfer to son level */
+       son = &f->fields[type];
+       if (son->attr & STOP) {
+               PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name);
+               return H323_ERROR_STOP;
+       }
+
+       if (ext || (son->attr & OPEN)) {
+               BYTE_ALIGN(bs);
+               len = get_len(bs);
+               CHECK_BOUND(bs, len);
+               if (!base || !(son->attr & DECODE)) {
+                       PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
+                             son->name);
+                       bs->cur += len;
+                       return H323_ERROR_NONE;
+               }
+               beg = bs->cur;
+
+               if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) >
+                   H323_ERROR_STOP)
+                       return err;
+
+               bs->cur = beg + len;
+               bs->bit = 0;
+       } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)))
+               return err;
+
+       return H323_ERROR_NONE;
+}
+
+/****************************************************************************/
+int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras)
+{
+       static field_t ras_message = {
+               FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT,
+               0, _RasMessage
+       };
+       bitstr_t bs;
+
+       bs.buf = bs.beg = bs.cur = buf;
+       bs.end = buf + sz;
+       bs.bit = 0;
+
+       return decode_choice(&bs, &ras_message, (char *) ras, 0);
+}
+
+/****************************************************************************/
+static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg,
+                                     size_t sz, H323_UserInformation * uuie)
+{
+       static field_t h323_userinformation = {
+               FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT,
+               0, _H323_UserInformation
+       };
+       bitstr_t bs;
+
+       bs.buf = buf;
+       bs.beg = bs.cur = beg;
+       bs.end = beg + sz;
+       bs.bit = 0;
+
+       return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0);
+}
+
+/****************************************************************************/
+int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
+                                        MultimediaSystemControlMessage *
+                                        mscm)
+{
+       static field_t multimediasystemcontrolmessage = {
+               FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4,
+               DECODE | EXT, 0, _MultimediaSystemControlMessage
+       };
+       bitstr_t bs;
+
+       bs.buf = bs.beg = bs.cur = buf;
+       bs.end = buf + sz;
+       bs.bit = 0;
+
+       return decode_choice(&bs, &multimediasystemcontrolmessage,
+                            (char *) mscm, 0);
+}
+
+/****************************************************************************/
+int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931)
+{
+       unsigned char *p = buf;
+       int len;
+
+       if (!p || sz < 1)
+               return H323_ERROR_BOUND;
+
+       /* Protocol Discriminator */
+       if (*p != 0x08) {
+               PRINT("Unknown Protocol Discriminator\n");
+               return H323_ERROR_RANGE;
+       }
+       p++;
+       sz--;
+
+       /* CallReferenceValue */
+       if (sz < 1)
+               return H323_ERROR_BOUND;
+       len = *p++;
+       sz--;
+       if (sz < len)
+               return H323_ERROR_BOUND;
+       p += len;
+       sz -= len;
+
+       /* Message Type */
+       if (sz < 1)
+               return H323_ERROR_BOUND;
+       q931->MessageType = *p++;
+       PRINT("MessageType = %02X\n", q931->MessageType);
+       if (*p & 0x80) {
+               p++;
+               sz--;
+       }
+
+       /* Decode Information Elements */
+       while (sz > 0) {
+               if (*p == 0x7e) {       /* UserUserIE */
+                       if (sz < 3)
+                               break;
+                       p++;
+                       len = *p++ << 8;
+                       len |= *p++;
+                       sz -= 3;
+                       if (sz < len)
+                               break;
+                       p++;
+                       len--;
+                       return DecodeH323_UserInformation(buf, p, len,
+                                                         &q931->UUIE);
+               }
+               p++;
+               sz--;
+               if (sz < 1)
+                       break;
+               len = *p++;
+               if (sz < len)
+                       break;
+               p += len;
+               sz -= len;
+       }
+
+       PRINT("Q.931 UUIE not found\n");
+
+       return H323_ERROR_BOUND;
+}
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h
new file mode 100644 (file)
index 0000000..0bd8280
--- /dev/null
@@ -0,0 +1,98 @@
+/****************************************************************************
+ * ip_conntrack_helper_h323_asn1.h - BER and PER decoding library for H.323
+ *                                  conntrack/NAT module.
+ *
+ * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@hotmail.com>
+ *
+ * This source code is licensed under General Public License version 2.
+ *
+ *
+ * This library is based on H.225 version 4, H.235 version 2 and H.245
+ * version 7. It is extremely optimized to decode only the absolutely
+ * necessary objects in a signal for Linux kernel NAT module use, so don't
+ * expect it to be a full ASN.1 library.
+ *
+ * Features:
+ *
+ * 1. Small. The total size of code plus data is less than 20 KB (IA32).
+ * 2. Fast. Decoding Netmeeting's Setup signal 1 million times on a PIII 866
+ *    takes only 3.9 seconds.
+ * 3. No memory allocation. It uses a static object. No need to initialize or
+ *    cleanup.
+ * 4. Thread safe.
+ * 5. Support embedded architectures that has no misaligned memory access
+ *    support.
+ *
+ * Limitations:
+ *
+ * 1. At most 30 faststart entries. Actually this is limited by ethernet's MTU.
+ *    If a Setup signal contains more than 30 faststart, the packet size will
+ *    very likely exceed the MTU size, then the TPKT will be fragmented. I
+ *    don't know how to handle this in a Netfilter module. Anybody can help?
+ *    Although I think 30 is enough for most of the cases.
+ * 2. IPv4 addresses only.
+ *
+ ****************************************************************************/
+
+#ifndef _IP_CONNTRACK_HELPER_H323_ASN1_H_
+#define _IP_CONNTRACK_HELPER_H323_ASN1_H_
+
+/*****************************************************************************
+ * H.323 Types
+ ****************************************************************************/
+#include "ip_conntrack_helper_h323_types.h"
+
+typedef struct {
+       enum {
+               Q931_NationalEscape = 0x00,
+               Q931_Alerting = 0x01,
+               Q931_CallProceeding = 0x02,
+               Q931_Connect = 0x07,
+               Q931_ConnectAck = 0x0F,
+               Q931_Progress = 0x03,
+               Q931_Setup = 0x05,
+               Q931_SetupAck = 0x0D,
+               Q931_Resume = 0x26,
+               Q931_ResumeAck = 0x2E,
+               Q931_ResumeReject = 0x22,
+               Q931_Suspend = 0x25,
+               Q931_SuspendAck = 0x2D,
+               Q931_SuspendReject = 0x21,
+               Q931_UserInformation = 0x20,
+               Q931_Disconnect = 0x45,
+               Q931_Release = 0x4D,
+               Q931_ReleaseComplete = 0x5A,
+               Q931_Restart = 0x46,
+               Q931_RestartAck = 0x4E,
+               Q931_Segment = 0x60,
+               Q931_CongestionCtrl = 0x79,
+               Q931_Information = 0x7B,
+               Q931_Notify = 0x6E,
+               Q931_Status = 0x7D,
+               Q931_StatusEnquiry = 0x75,
+               Q931_Facility = 0x62
+       } MessageType;
+       H323_UserInformation UUIE;
+} Q931;
+
+/*****************************************************************************
+ * Decode Functions Return Codes
+ ****************************************************************************/
+
+#define H323_ERROR_NONE 0      /* Decoded successfully */
+#define H323_ERROR_STOP 1      /* Decoding stopped, not really an error */
+#define H323_ERROR_BOUND -1
+#define H323_ERROR_RANGE -2
+
+
+/*****************************************************************************
+ * Decode Functions
+ ****************************************************************************/
+
+int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras);
+int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931);
+int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
+                                        MultimediaSystemControlMessage *
+                                        mscm);
+
+#endif
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c
new file mode 100644 (file)
index 0000000..022c47b
--- /dev/null
@@ -0,0 +1,1926 @@
+/* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006
+ *
+ * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ *
+ * This source code is licensed under General Public License version 2.
+ */
+
+static field_t _TransportAddress_ipAddress[] = {       /* SEQUENCE */
+       {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE,
+        offsetof(TransportAddress_ipAddress, ip), NULL},
+       {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _TransportAddress_ipSourceRoute_route[] = {     /* SEQUENCE OF */
+       {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+};
+
+static field_t _TransportAddress_ipSourceRoute_routing[] = {   /* CHOICE */
+       {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _TransportAddress_ipSourceRoute[] = {   /* SEQUENCE */
+       {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+       {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
+       {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0,
+        _TransportAddress_ipSourceRoute_route},
+       {FNAME("routing") CHOICE, 1, 2, 2, SKIP | EXT, 0,
+        _TransportAddress_ipSourceRoute_routing},
+};
+
+static field_t _TransportAddress_ipxAddress[] = {      /* SEQUENCE */
+       {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL},
+       {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+       {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL},
+};
+
+static field_t _TransportAddress_ip6Address[] = {      /* SEQUENCE */
+       {FNAME("ip") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+       {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H221NonStandard[] = {  /* SEQUENCE */
+       {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _NonStandardIdentifier[] = {    /* CHOICE */
+       {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0,
+        _H221NonStandard},
+};
+
+static field_t _NonStandardParameter[] = {     /* SEQUENCE */
+       {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0,
+        _NonStandardIdentifier},
+       {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _TransportAddress[] = { /* CHOICE */
+       {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE,
+        offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress},
+       {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0,
+        _TransportAddress_ipSourceRoute},
+       {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0,
+        _TransportAddress_ipxAddress},
+       {FNAME("ip6Address") SEQ, 0, 2, 2, SKIP | EXT, 0,
+        _TransportAddress_ip6Address},
+       {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+       {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL},
+       {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0,
+        _NonStandardParameter},
+};
+
+static field_t _AliasAddress[] = {     /* CHOICE */
+       {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL},
+       {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("transportID") CHOICE, 3, 7, 7, SKIP | EXT, 0, NULL},
+       {FNAME("email-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("partyNumber") CHOICE, 3, 5, 5, SKIP | EXT, 0, NULL},
+       {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL},
+};
+
+static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _VendorIdentifier[] = { /* SEQUENCE */
+       {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard},
+       {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _GatekeeperInfo[] = {   /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+};
+
+static field_t _H310Caps[] = { /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H320Caps[] = { /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H321Caps[] = { /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H322Caps[] = { /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H323Caps[] = { /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H324Caps[] = { /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _VoiceCaps[] = {        /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _T120OnlyCaps[] = {     /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _SupportedProtocols[] = {       /* CHOICE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0,
+        _NonStandardParameter},
+       {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps},
+       {FNAME("h320") SEQ, 1, 1, 3, SKIP | EXT, 0, _H320Caps},
+       {FNAME("h321") SEQ, 1, 1, 3, SKIP | EXT, 0, _H321Caps},
+       {FNAME("h322") SEQ, 1, 1, 3, SKIP | EXT, 0, _H322Caps},
+       {FNAME("h323") SEQ, 1, 1, 3, SKIP | EXT, 0, _H323Caps},
+       {FNAME("h324") SEQ, 1, 1, 3, SKIP | EXT, 0, _H324Caps},
+       {FNAME("voice") SEQ, 1, 1, 3, SKIP | EXT, 0, _VoiceCaps},
+       {FNAME("t120-only") SEQ, 1, 1, 3, SKIP | EXT, 0, _T120OnlyCaps},
+       {FNAME("nonStandardProtocol") SEQ, 2, 3, 3, SKIP | EXT, 0, NULL},
+       {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL},
+};
+
+static field_t _GatewayInfo_protocol[] = {     /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols},
+};
+
+static field_t _GatewayInfo[] = {      /* SEQUENCE */
+       {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _GatewayInfo_protocol},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+};
+
+static field_t _McuInfo[] = {  /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _TerminalInfo[] = {     /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+};
+
+static field_t _EndpointType[] = {     /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0,
+        _VendorIdentifier},
+       {FNAME("gatekeeper") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0,
+        _GatekeeperInfo},
+       {FNAME("gateway") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, _GatewayInfo},
+       {FNAME("mcu") SEQ, 1, 1, 2, SKIP | EXT | OPT, 0, _McuInfo},
+       {FNAME("terminal") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, _TerminalInfo},
+       {FNAME("mc") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("undefinedNode") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("set") BITSTR, FIXD, 32, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedTunnelledProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT,
+        0, NULL},
+};
+
+static field_t _Setup_UUIE_destinationAddress[] = {    /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _Setup_UUIE_destExtraCallInfo[] = {     /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _Setup_UUIE_destExtraCRV[] = {  /* SEQUENCE OF */
+       {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _Setup_UUIE_conferenceGoal[] = {        /* CHOICE */
+       {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("capability-negotiation") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("callIndependentSupplementaryService") NUL, FIXD, 0, 0, SKIP,
+        0, NULL},
+};
+
+static field_t _Q954Details[] = {      /* SEQUENCE */
+       {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _QseriesOptions[] = {   /* SEQUENCE */
+       {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("q953Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("q955Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("q956Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("q957Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details},
+};
+
+static field_t _CallType[] = { /* CHOICE */
+       {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H245_NonStandardIdentifier_h221NonStandard[] = {       /* SEQUENCE */
+       {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H245_NonStandardIdentifier[] = {       /* CHOICE */
+       {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0,
+        _H245_NonStandardIdentifier_h221NonStandard},
+};
+
+static field_t _H245_NonStandardParameter[] = {        /* SEQUENCE */
+       {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0,
+        _H245_NonStandardIdentifier},
+       {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H261VideoCapability[] = {      /* SEQUENCE */
+       {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0,
+        NULL},
+       {FNAME("maxBitRate") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("stillImageTransmission") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H262VideoCapability[] = {      /* SEQUENCE */
+       {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-MPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-MPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-SNRatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-SNRatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-SpatialatH-14") BOOL, FIXD, 0, 0, SKIP, 0,
+        NULL},
+       {FNAME("profileAndLevel-HPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-HPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("profileAndLevel-HPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("framesPerSecond") INT, 4, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H263VideoCapability[] = {      /* SEQUENCE */
+       {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cif4MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cif16MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("maxBitRate") INT, CONS, 1, 0, SKIP, 0, NULL},
+       {FNAME("unrestrictedVector") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("arithmeticCoding") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("advancedPrediction") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("pbFrames") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0,
+        NULL},
+       {FNAME("hrd-B") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("bppMaxKb") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("slowSqcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("slowQcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("slowCifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("slowCif4MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("slowCif16MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("errorCompensation") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("enhancementLayerInfo") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL},
+};
+
+static field_t _IS11172VideoCapability[] = {   /* SEQUENCE */
+       {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("pictureRate") INT, 4, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _VideoCapability[] = {  /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+        _H245_NonStandardParameter},
+       {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0,
+        _H261VideoCapability},
+       {FNAME("h262VideoCapability") SEQ, 6, 17, 18, SKIP | EXT, 0,
+        _H262VideoCapability},
+       {FNAME("h263VideoCapability") SEQ, 7, 13, 21, SKIP | EXT, 0,
+        _H263VideoCapability},
+       {FNAME("is11172VideoCapability") SEQ, 6, 7, 8, SKIP | EXT, 0,
+        _IS11172VideoCapability},
+       {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL},
+};
+
+static field_t _AudioCapability_g7231[] = {    /* SEQUENCE */
+       {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _IS11172AudioCapability[] = {   /* SEQUENCE */
+       {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL},
+};
+
+static field_t _IS13818AudioCapability[] = {   /* SEQUENCE */
+       {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling16k") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling22k05") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling24k") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("threeChannels2-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("threeChannels3-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("fourChannels2-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("fourChannels2-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("fourChannels3-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("fiveChannels3-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("fiveChannels3-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("lowFrequencyEnhancement") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("multilingual") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL},
+};
+
+static field_t _AudioCapability[] = {  /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+        _H245_NonStandardParameter},
+       {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g711Alaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g711Ulaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g711Ulaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g722-64k") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g722-56k") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g722-48k") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g7231") SEQ, 0, 2, 2, SKIP, 0, _AudioCapability_g7231},
+       {FNAME("g728") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g729") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g729AnnexA") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("is11172AudioCapability") SEQ, 0, 9, 9, SKIP | EXT, 0,
+        _IS11172AudioCapability},
+       {FNAME("is13818AudioCapability") SEQ, 0, 21, 21, SKIP | EXT, 0,
+        _IS13818AudioCapability},
+       {FNAME("g729wAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g729AnnexAwAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL},
+       {FNAME("g7231AnnexCCapability") SEQ, 1, 3, 3, SKIP | EXT, 0, NULL},
+       {FNAME("gsmFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL},
+       {FNAME("gsmHalfRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL},
+       {FNAME("gsmEnhancedFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL},
+       {FNAME("genericAudioCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL},
+       {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL},
+};
+
+static field_t _DataProtocolCapability[] = {   /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+        _H245_NonStandardParameter},
+       {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("v42lapm") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("hdlcFrameTunnelling") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("h310SeparateVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("h310SingleVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("transparent") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("segmentationAndReassembly") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("hdlcFrameTunnelingwSAR") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("v120") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("separateLANStack") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("v76wCompression") CHOICE, 2, 3, 3, SKIP | EXT, 0, NULL},
+       {FNAME("tcp") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */
+       {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("ccir601Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("hdtvSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("hdtvProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("g3FacsMH200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("g3FacsMH200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("g4FacsMMR200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("g4FacsMMR200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("jbig200x200Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("jbig200x200Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("jbig300x300Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("jbig300x300Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("digPhotoLow") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("digPhotoMedSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("digPhotoMedProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("digPhotoHighSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _T84Profile[] = {       /* CHOICE */
+       {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0,
+        _T84Profile_t84Restricted},
+};
+
+static field_t _DataApplicationCapability_application_t84[] = {        /* SEQUENCE */
+       {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+        _DataProtocolCapability},
+       {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile},
+};
+
+static field_t _DataApplicationCapability_application_nlpid[] = {      /* SEQUENCE */
+       {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+        _DataProtocolCapability},
+       {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _DataApplicationCapability_application[] = {    /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+        _H245_NonStandardParameter},
+       {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT,
+        offsetof(DataApplicationCapability_application, t120),
+        _DataProtocolCapability},
+       {FNAME("dsm-cc") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+        _DataProtocolCapability},
+       {FNAME("userData") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+        _DataProtocolCapability},
+       {FNAME("t84") SEQ, 0, 2, 2, SKIP, 0,
+        _DataApplicationCapability_application_t84},
+       {FNAME("t434") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+        _DataProtocolCapability},
+       {FNAME("h224") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+        _DataProtocolCapability},
+       {FNAME("nlpid") SEQ, 0, 2, 2, SKIP, 0,
+        _DataApplicationCapability_application_nlpid},
+       {FNAME("dsvdControl") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("h222DataPartitioning") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+        _DataProtocolCapability},
+       {FNAME("t30fax") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL},
+       {FNAME("t140") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL},
+       {FNAME("t38fax") SEQ, 0, 2, 2, SKIP, 0, NULL},
+       {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL},
+};
+
+static field_t _DataApplicationCapability[] = {        /* SEQUENCE */
+       {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT,
+        offsetof(DataApplicationCapability, application),
+        _DataApplicationCapability_application},
+       {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _EncryptionMode[] = {   /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+        _H245_NonStandardParameter},
+       {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _DataType[] = { /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+        _H245_NonStandardParameter},
+       {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("videoData") CHOICE, 3, 5, 6, SKIP | EXT, 0, _VideoCapability},
+       {FNAME("audioData") CHOICE, 4, 14, 22, SKIP | EXT, 0,
+        _AudioCapability},
+       {FNAME("data") SEQ, 0, 2, 2, DECODE | EXT, offsetof(DataType, data),
+        _DataApplicationCapability},
+       {FNAME("encryptionData") CHOICE, 1, 2, 2, SKIP | EXT, 0,
+        _EncryptionMode},
+       {FNAME("h235Control") SEQ, 0, 2, 2, SKIP, 0, NULL},
+       {FNAME("h235Media") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL},
+       {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL},
+};
+
+static field_t _H222LogicalChannelParameters[] = {     /* SEQUENCE */
+       {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL},
+       {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL},
+       {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("programDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = {     /* SEQUENCE */
+       {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL},
+       {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+        _H245_NonStandardParameter},
+       {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("al1NotFramed") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("al2WithoutSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("al2WithSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("al3") SEQ, 0, 2, 2, SKIP, 0,
+        _H223LogicalChannelParameters_adaptationLayerType_al3},
+       {FNAME("al1M") SEQ, 0, 7, 8, SKIP | EXT, 0, NULL},
+       {FNAME("al2M") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL},
+       {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL},
+};
+
+static field_t _H223LogicalChannelParameters[] = {     /* SEQUENCE */
+       {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0,
+        _H223LogicalChannelParameters_adaptationLayerType},
+       {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CRCLength[] = {        /* CHOICE */
+       {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _V76HDLCParameters[] = {        /* SEQUENCE */
+       {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength},
+       {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _V76LogicalChannelParameters_suspendResume[] = {        /* CHOICE */
+       {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = {    /* CHOICE */
+       {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _V76LogicalChannelParameters_mode_eRM[] = {     /* SEQUENCE */
+       {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL},
+       {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0,
+        _V76LogicalChannelParameters_mode_eRM_recovery},
+};
+
+static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */
+       {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0,
+        _V76LogicalChannelParameters_mode_eRM},
+       {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _V75Parameters[] = {    /* SEQUENCE */
+       {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _V76LogicalChannelParameters[] = {      /* SEQUENCE */
+       {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0,
+        _V76HDLCParameters},
+       {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0,
+        _V76LogicalChannelParameters_suspendResume},
+       {FNAME("uIH") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("mode") CHOICE, 1, 2, 2, SKIP | EXT, 0,
+        _V76LogicalChannelParameters_mode},
+       {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters},
+};
+
+static field_t _H2250LogicalChannelParameters_nonStandard[] = {        /* SEQUENCE OF */
+       {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter},
+};
+
+static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */
+       {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE,
+        offsetof(UnicastAddress_iPAddress, network), NULL},
+       {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _UnicastAddress_iPXAddress[] = {        /* SEQUENCE */
+       {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL},
+       {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+       {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL},
+};
+
+static field_t _UnicastAddress_iP6Address[] = {        /* SEQUENCE */
+       {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+       {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = {      /* CHOICE */
+       {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _UnicastAddress_iPSourceRouteAddress_route[] = {        /* SEQUENCE OF */
+       {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+};
+
+static field_t _UnicastAddress_iPSourceRouteAddress[] = {      /* SEQUENCE */
+       {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0,
+        _UnicastAddress_iPSourceRouteAddress_routing},
+       {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+       {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+       {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0,
+        _UnicastAddress_iPSourceRouteAddress_route},
+};
+
+static field_t _UnicastAddress[] = {   /* CHOICE */
+       {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT,
+        offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress},
+       {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0,
+        _UnicastAddress_iPXAddress},
+       {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0,
+        _UnicastAddress_iP6Address},
+       {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+       {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0,
+        _UnicastAddress_iPSourceRouteAddress},
+       {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL},
+       {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL},
+};
+
+static field_t _MulticastAddress_iPAddress[] = {       /* SEQUENCE */
+       {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+       {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _MulticastAddress_iP6Address[] = {      /* SEQUENCE */
+       {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+       {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _MulticastAddress[] = { /* CHOICE */
+       {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0,
+        _MulticastAddress_iPAddress},
+       {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0,
+        _MulticastAddress_iP6Address},
+       {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL},
+       {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL},
+};
+
+static field_t _H245_TransportAddress[] = {    /* CHOICE */
+       {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT,
+        offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress},
+       {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0,
+        _MulticastAddress},
+};
+
+static field_t _H2250LogicalChannelParameters[] = {    /* SEQUENCE */
+       {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _H2250LogicalChannelParameters_nonStandard},
+       {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("associatedSessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT,
+        offsetof(H2250LogicalChannelParameters, mediaChannel),
+        _H245_TransportAddress},
+       {FNAME("mediaGuaranteedDelivery") BOOL, FIXD, 0, 0, SKIP | OPT, 0,
+        NULL},
+       {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT,
+        offsetof(H2250LogicalChannelParameters, mediaControlChannel),
+        _H245_TransportAddress},
+       {FNAME("mediaControlGuaranteedDelivery") BOOL, FIXD, 0, 0, STOP | OPT,
+        0, NULL},
+       {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("destination") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL},
+       {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, STOP | OPT, 0, NULL},
+       {FNAME("mediaPacketization") CHOICE, 0, 1, 2, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("transportCapability") SEQ, 3, 3, 3, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("redundancyEncoding") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, NULL},
+       {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL},
+};
+
+static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = {   /* CHOICE */
+       {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0,
+        _H222LogicalChannelParameters},
+       {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0,
+        _H223LogicalChannelParameters},
+       {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0,
+        _V76LogicalChannelParameters},
+       {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT,
+        offsetof
+        (OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters,
+         h2250LogicalChannelParameters), _H2250LogicalChannelParameters},
+       {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = {       /* SEQUENCE */
+       {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT,
+        offsetof(OpenLogicalChannel_forwardLogicalChannelParameters,
+                 dataType), _DataType},
+       {FNAME("multiplexParameters") CHOICE, 2, 3, 5, DECODE | EXT,
+        offsetof(OpenLogicalChannel_forwardLogicalChannelParameters,
+                 multiplexParameters),
+        _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters},
+       {FNAME("forwardLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT,
+        0, NULL},
+       {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = {   /* CHOICE */
+       {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0,
+        _H223LogicalChannelParameters},
+       {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0,
+        _V76LogicalChannelParameters},
+       {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT,
+        offsetof
+        (OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters,
+         h2250LogicalChannelParameters), _H2250LogicalChannelParameters},
+};
+
+static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = {       /* SEQUENCE */
+       {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType},
+       {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT,
+        offsetof(OpenLogicalChannel_reverseLogicalChannelParameters,
+                 multiplexParameters),
+        _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters},
+       {FNAME("reverseLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT,
+        0, NULL},
+       {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _NetworkAccessParameters_distribution[] = {     /* CHOICE */
+       {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _Q2931Address_address[] = {     /* CHOICE */
+       {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL},
+       {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL},
+};
+
+static field_t _Q2931Address[] = {     /* SEQUENCE */
+       {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0,
+        _Q2931Address_address},
+       {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _NetworkAccessParameters_networkAddress[] = {   /* CHOICE */
+       {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address},
+       {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL},
+       {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT,
+        offsetof(NetworkAccessParameters_networkAddress, localAreaAddress),
+        _H245_TransportAddress},
+};
+
+static field_t _NetworkAccessParameters[] = {  /* SEQUENCE */
+       {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0,
+        _NetworkAccessParameters_distribution},
+       {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT,
+        offsetof(NetworkAccessParameters, networkAddress),
+        _NetworkAccessParameters_networkAddress},
+       {FNAME("associateConference") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("externalReference") OCTSTR, 8, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("t120SetupProcedure") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0,
+        NULL},
+};
+
+static field_t _OpenLogicalChannel[] = {       /* SEQUENCE */
+       {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT,
+        offsetof(OpenLogicalChannel, forwardLogicalChannelParameters),
+        _OpenLogicalChannel_forwardLogicalChannelParameters},
+       {FNAME("reverseLogicalChannelParameters") SEQ, 1, 2, 4,
+        DECODE | EXT | OPT, offsetof(OpenLogicalChannel,
+                                     reverseLogicalChannelParameters),
+        _OpenLogicalChannel_reverseLogicalChannelParameters},
+       {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT,
+        offsetof(OpenLogicalChannel, separateStack),
+        _NetworkAccessParameters},
+       {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL},
+};
+
+static field_t _Setup_UUIE_fastStart[] = {     /* SEQUENCE OF */
+       {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+        sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+       ,
+};
+
+static field_t _Setup_UUIE[] = {       /* SEQUENCE */
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(Setup_UUIE, h245Address), _TransportAddress},
+       {FNAME("sourceAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _Setup_UUIE_sourceAddress},
+       {FNAME("sourceInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType},
+       {FNAME("destinationAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _Setup_UUIE_destinationAddress},
+       {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(Setup_UUIE, destCallSignalAddress), _TransportAddress},
+       {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _Setup_UUIE_destExtraCallInfo},
+       {FNAME("destExtraCRV") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _Setup_UUIE_destExtraCRV},
+       {FNAME("activeMC") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+       {FNAME("conferenceGoal") CHOICE, 2, 3, 5, SKIP | EXT, 0,
+        _Setup_UUIE_conferenceGoal},
+       {FNAME("callServices") SEQ, 0, 8, 8, SKIP | EXT | OPT, 0,
+        _QseriesOptions},
+       {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType},
+       {FNAME("sourceCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(Setup_UUIE, sourceCallSignalAddress), _TransportAddress},
+       {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
+       {FNAME("h245SecurityCapability") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT,
+        offsetof(Setup_UUIE, fastStart), _Setup_UUIE_fastStart},
+       {FNAME("mediaWaitForConnect") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("canOverlapSend") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("connectionParameters") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("symmetricOperationRequired") NUL, FIXD, 0, 0, SKIP | OPT, 0,
+        NULL},
+       {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("neededFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("desiredFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("supportedFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("parallelH245Control") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("additionalSourceAddresses") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        NULL},
+};
+
+static field_t _CallProceeding_UUIE_fastStart[] = {    /* SEQUENCE OF */
+       {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+        sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+       ,
+};
+
+static field_t _CallProceeding_UUIE[] = {      /* SEQUENCE */
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
+        _EndpointType},
+       {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(CallProceeding_UUIE, h245Address), _TransportAddress},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
+       {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT,
+        offsetof(CallProceeding_UUIE, fastStart),
+        _CallProceeding_UUIE_fastStart},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+};
+
+static field_t _Connect_UUIE_fastStart[] = {   /* SEQUENCE OF */
+       {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+        sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+       ,
+};
+
+static field_t _Connect_UUIE[] = {     /* SEQUENCE */
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(Connect_UUIE, h245Address), _TransportAddress},
+       {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
+        _EndpointType},
+       {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
+       {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT,
+        offsetof(Connect_UUIE, fastStart), _Connect_UUIE_fastStart},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("connectedAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+};
+
+static field_t _Alerting_UUIE_fastStart[] = {  /* SEQUENCE OF */
+       {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+        sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+       ,
+};
+
+static field_t _Alerting_UUIE[] = {    /* SEQUENCE */
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
+        _EndpointType},
+       {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(Alerting_UUIE, h245Address), _TransportAddress},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
+       {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT,
+        offsetof(Alerting_UUIE, fastStart), _Alerting_UUIE_fastStart},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("alertingAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+};
+
+static field_t _Information_UUIE_fastStart[] = {       /* SEQUENCE OF */
+       {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+        sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+       ,
+};
+
+static field_t _Information_UUIE[] = { /* SEQUENCE */
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT,
+        offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart},
+       {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL},
+};
+
+static field_t _ReleaseCompleteReason[] = {    /* CHOICE */
+       {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("destinationRejection") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("invalidRevision") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("noPermission") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("unreachableGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("gatewayResources") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("badFormatAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("adaptiveBusy") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("inConf") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("facilityCallDeflection") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("securityDenied") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("calledPartyNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("callerNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("newConnectionNeeded") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("nonStandardReason") SEQ, 0, 2, 2, SKIP, 0, NULL},
+       {FNAME("replaceWithConferenceInvite") OCTSTR, FIXD, 16, 0, SKIP, 0,
+        NULL},
+       {FNAME("genericDataReason") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("neededFeatureNotSupported") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _ReleaseComplete_UUIE[] = {     /* SEQUENCE */
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0,
+        _ReleaseCompleteReason},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("busyAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+};
+
+static field_t _Facility_UUIE_alternativeAliasAddress[] = {    /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _FacilityReason[] = {   /* CHOICE */
+       {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("conferenceListChoice") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("startH245") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("noH245") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("newTokens") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("featureSetUpdate") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("forwardedElements") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _Facility_UUIE_fastStart[] = {  /* SEQUENCE OF */
+       {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+        sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+       ,
+};
+
+static field_t _Facility_UUIE[] = {    /* SEQUENCE */
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("alternativeAddress") CHOICE, 3, 7, 7, SKIP | EXT | OPT, 0,
+        _TransportAddress},
+       {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _Facility_UUIE_alternativeAliasAddress},
+       {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL},
+       {FNAME("reason") CHOICE, 2, 4, 11, DECODE | EXT,
+        offsetof(Facility_UUIE, reason), _FacilityReason},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
+       {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0,
+        NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("conferences") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(Facility_UUIE, h245Address), _TransportAddress},
+       {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT,
+        offsetof(Facility_UUIE, fastStart), _Facility_UUIE_fastStart},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0,
+        NULL},
+};
+
+static field_t _CallIdentifier[] = {   /* SEQUENCE */
+       {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+};
+
+static field_t _SecurityServiceMode[] = {      /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter},
+       {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _SecurityCapabilities[] = {     /* SEQUENCE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0,
+        _SecurityServiceMode},
+       {FNAME("authenticaton") CHOICE, 2, 3, 3, SKIP | EXT, 0,
+        _SecurityServiceMode},
+       {FNAME("integrity") CHOICE, 2, 3, 3, SKIP | EXT, 0,
+        _SecurityServiceMode},
+};
+
+static field_t _H245Security[] = {     /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter},
+       {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities},
+       {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities},
+};
+
+static field_t _DHset[] = {    /* SEQUENCE */
+       {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
+       {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
+       {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _TypedCertificate[] = { /* SEQUENCE */
+       {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _H235_NonStandardParameter[] = {        /* SEQUENCE */
+       {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _ClearToken[] = {       /* SEQUENCE */
+       {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("dhkey") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, _DHset},
+       {FNAME("challenge") OCTSTR, 7, 8, 0, SKIP | OPT, 0, NULL},
+       {FNAME("random") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("certificate") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0,
+        _TypedCertificate},
+       {FNAME("generalID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _H235_NonStandardParameter},
+       {FNAME("eckasdhkey") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _Progress_UUIE_tokens[] = {     /* SEQUENCE OF */
+       {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken},
+};
+
+static field_t _Params[] = {   /* SEQUENCE */
+       {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL},
+       {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = {    /* SEQUENCE */
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoH323Token_cryptoEPPwdHash[] = {  /* SEQUENCE */
+       {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+       {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL},
+       {FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoH323Token_cryptoEPPwdHash_token},
+};
+
+static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = {    /* SEQUENCE */
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoH323Token_cryptoGKPwdHash[] = {  /* SEQUENCE */
+       {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL},
+       {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL},
+       {FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoH323Token_cryptoGKPwdHash_token},
+};
+
+static field_t _CryptoH323Token_cryptoEPPwdEncr[] = {  /* SEQUENCE */
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoH323Token_cryptoGKPwdEncr[] = {  /* SEQUENCE */
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoH323Token_cryptoEPCert[] = {     /* SEQUENCE */
+       {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoH323Token_cryptoGKCert[] = {     /* SEQUENCE */
+       {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoH323Token_cryptoFastStart[] = {  /* SEQUENCE */
+       {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoToken_cryptoEncryptedToken_token[] = {   /* SEQUENCE */
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */
+       {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoToken_cryptoEncryptedToken_token},
+};
+
+static field_t _CryptoToken_cryptoSignedToken_token[] = {      /* SEQUENCE */
+       {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoToken_cryptoSignedToken[] = {    /* SEQUENCE */
+       {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("token") SEQ, 0, 4, 4, SKIP, 0,
+        _CryptoToken_cryptoSignedToken_token},
+};
+
+static field_t _CryptoToken_cryptoHashedToken_token[] = {      /* SEQUENCE */
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoToken_cryptoHashedToken[] = {    /* SEQUENCE */
+       {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken},
+       {FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoToken_cryptoHashedToken_token},
+};
+
+static field_t _CryptoToken_cryptoPwdEncr[] = {        /* SEQUENCE */
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+       {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _CryptoToken[] = {      /* CHOICE */
+       {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0,
+        _CryptoToken_cryptoEncryptedToken},
+       {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0,
+        _CryptoToken_cryptoSignedToken},
+       {FNAME("cryptoHashedToken") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoToken_cryptoHashedToken},
+       {FNAME("cryptoPwdEncr") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoToken_cryptoPwdEncr},
+};
+
+static field_t _CryptoH323Token[] = {  /* CHOICE */
+       {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoH323Token_cryptoEPPwdHash},
+       {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoH323Token_cryptoGKPwdHash},
+       {FNAME("cryptoEPPwdEncr") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoH323Token_cryptoEPPwdEncr},
+       {FNAME("cryptoGKPwdEncr") SEQ, 0, 3, 3, SKIP, 0,
+        _CryptoH323Token_cryptoGKPwdEncr},
+       {FNAME("cryptoEPCert") SEQ, 0, 4, 4, SKIP, 0,
+        _CryptoH323Token_cryptoEPCert},
+       {FNAME("cryptoGKCert") SEQ, 0, 4, 4, SKIP, 0,
+        _CryptoH323Token_cryptoGKCert},
+       {FNAME("cryptoFastStart") SEQ, 0, 4, 4, SKIP, 0,
+        _CryptoH323Token_cryptoFastStart},
+       {FNAME("nestedcryptoToken") CHOICE, 2, 4, 4, SKIP | EXT, 0,
+        _CryptoToken},
+};
+
+static field_t _Progress_UUIE_cryptoTokens[] = {       /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token},
+};
+
+static field_t _Progress_UUIE_fastStart[] = {  /* SEQUENCE OF */
+       {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+        sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+       ,
+};
+
+static field_t _Progress_UUIE[] = {    /* SEQUENCE */
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
+        _EndpointType},
+       {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(Progress_UUIE, h245Address), _TransportAddress},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0,
+        _CallIdentifier},
+       {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0,
+        _H245Security},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _Progress_UUIE_tokens},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _Progress_UUIE_cryptoTokens},
+       {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT,
+        offsetof(Progress_UUIE, fastStart), _Progress_UUIE_fastStart},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _H323_UU_PDU_h323_message_body[] = {    /* CHOICE */
+       {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT,
+        offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE},
+       {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT,
+        offsetof(H323_UU_PDU_h323_message_body, callProceeding),
+        _CallProceeding_UUIE},
+       {FNAME("connect") SEQ, 1, 4, 19, DECODE | EXT,
+        offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE},
+       {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT,
+        offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE},
+       {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT,
+        offsetof(H323_UU_PDU_h323_message_body, information),
+        _Information_UUIE},
+       {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0,
+        _ReleaseComplete_UUIE},
+       {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT,
+        offsetof(H323_UU_PDU_h323_message_body, facility), _Facility_UUIE},
+       {FNAME("progress") SEQ, 5, 8, 11, DECODE | EXT,
+        offsetof(H323_UU_PDU_h323_message_body, progress), _Progress_UUIE},
+       {FNAME("empty") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("status") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL},
+       {FNAME("statusInquiry") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL},
+       {FNAME("setupAcknowledge") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL},
+       {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL},
+};
+
+static field_t _RequestMessage[] = {   /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL},
+       {FNAME("openLogicalChannel") SEQ, 1, 3, 5, DECODE | EXT,
+        offsetof(RequestMessage, openLogicalChannel), _OpenLogicalChannel},
+       {FNAME("closeLogicalChannel") SEQ, 0, 2, 3, STOP | EXT, 0, NULL},
+       {FNAME("requestChannelClose") SEQ, 0, 1, 3, STOP | EXT, 0, NULL},
+       {FNAME("multiplexEntrySend") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("requestMultiplexEntry") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("requestMode") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("roundTripDelayRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("maintenanceLoopRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("communicationModeRequest") SEQ, 0, 0, 0, STOP | EXT, 0, NULL},
+       {FNAME("conferenceRequest") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL},
+       {FNAME("multilinkRequest") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL},
+       {FNAME("logicalChannelRateRequest") SEQ, 0, 3, 3, STOP | EXT, 0,
+        NULL},
+};
+
+static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = {        /* CHOICE */
+       {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0,
+        _H222LogicalChannelParameters},
+       {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT,
+        offsetof
+        (OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters,
+         h2250LogicalChannelParameters), _H2250LogicalChannelParameters},
+};
+
+static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = {    /* SEQUENCE */
+       {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT,
+        offsetof(OpenLogicalChannelAck_reverseLogicalChannelParameters,
+                 multiplexParameters),
+        _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters},
+       {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _H2250LogicalChannelAckParameters_nonStandard[] = {     /* SEQUENCE OF */
+       {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter},
+};
+
+static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */
+       {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _H2250LogicalChannelAckParameters_nonStandard},
+       {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT,
+        offsetof(H2250LogicalChannelAckParameters, mediaChannel),
+        _H245_TransportAddress},
+       {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT,
+        offsetof(H2250LogicalChannelAckParameters, mediaControlChannel),
+        _H245_TransportAddress},
+       {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, SKIP | OPT, 0, NULL},
+       {FNAME("flowControlToZero") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+};
+
+static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = {      /* CHOICE */
+       {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT,
+        offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters,
+                 h2250LogicalChannelAckParameters),
+        _H2250LogicalChannelAckParameters},
+};
+
+static field_t _OpenLogicalChannelAck[] = {    /* SEQUENCE */
+       {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4,
+        DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck,
+                                     reverseLogicalChannelParameters),
+        _OpenLogicalChannelAck_reverseLogicalChannelParameters},
+       {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL},
+       {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1,
+        DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck,
+                                     forwardMultiplexAckParameters),
+        _OpenLogicalChannelAck_forwardMultiplexAckParameters},
+       {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL},
+};
+
+static field_t _ResponseMessage[] = {  /* CHOICE */
+       {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0,
+        NULL},
+       {FNAME("masterSlaveDeterminationReject") SEQ, 0, 1, 1, STOP | EXT, 0,
+        NULL},
+       {FNAME("terminalCapabilitySetAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("terminalCapabilitySetReject") SEQ, 0, 2, 2, STOP | EXT, 0,
+        NULL},
+       {FNAME("openLogicalChannelAck") SEQ, 1, 2, 5, DECODE | EXT,
+        offsetof(ResponseMessage, openLogicalChannelAck),
+        _OpenLogicalChannelAck},
+       {FNAME("openLogicalChannelReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("closeLogicalChannelAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("requestChannelCloseAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("requestChannelCloseReject") SEQ, 0, 2, 2, STOP | EXT, 0,
+        NULL},
+       {FNAME("multiplexEntrySendAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("multiplexEntrySendReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("requestMultiplexEntryAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("requestMultiplexEntryReject") SEQ, 0, 2, 2, STOP | EXT, 0,
+        NULL},
+       {FNAME("requestModeAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("requestModeReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("roundTripDelayResponse") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("maintenanceLoopAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("maintenanceLoopReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+       {FNAME("communicationModeResponse") CHOICE, 0, 1, 1, STOP | EXT, 0,
+        NULL},
+       {FNAME("conferenceResponse") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL},
+       {FNAME("multilinkResponse") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL},
+       {FNAME("logicalChannelRateAcknowledge") SEQ, 0, 3, 3, STOP | EXT, 0,
+        NULL},
+       {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL},
+};
+
+static field_t _MultimediaSystemControlMessage[] = {   /* CHOICE */
+       {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT,
+        offsetof(MultimediaSystemControlMessage, request), _RequestMessage},
+       {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT,
+        offsetof(MultimediaSystemControlMessage, response),
+        _ResponseMessage},
+       {FNAME("command") CHOICE, 3, 7, 12, STOP | EXT, 0, NULL},
+       {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL},
+};
+
+static field_t _H323_UU_PDU_h245Control[] = {  /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT,
+        sizeof(MultimediaSystemControlMessage),
+        _MultimediaSystemControlMessage}
+       ,
+};
+
+static field_t _H323_UU_PDU[] = {      /* SEQUENCE */
+       {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT,
+        offsetof(H323_UU_PDU, h323_message_body),
+        _H323_UU_PDU_h323_message_body},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("h4501SupplementaryService") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        NULL},
+       {FNAME("h245Tunneling") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("h245Control") SEQOF, SEMI, 0, 4, DECODE | OPT,
+        offsetof(H323_UU_PDU, h245Control), _H323_UU_PDU_h245Control},
+       {FNAME("nonStandardControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL},
+       {FNAME("tunnelledSignallingMessage") SEQ, 2, 4, 4, STOP | EXT | OPT,
+        0, NULL},
+       {FNAME("provisionalRespToH245Tunneling") NUL, FIXD, 0, 0, STOP | OPT,
+        0, NULL},
+       {FNAME("stimulusControl") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _H323_UserInformation[] = {     /* SEQUENCE */
+       {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT,
+        offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU},
+       {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL},
+};
+
+static field_t _GatekeeperRequest[] = {        /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT,
+        offsetof(GatekeeperRequest, rasAddress), _TransportAddress},
+       {FNAME("endpointType") SEQ, 6, 8, 10, STOP | EXT, 0, NULL},
+       {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL},
+       {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("authenticationCapability") SEQOF, SEMI, 0, 0, STOP | OPT, 0,
+        NULL},
+       {FNAME("algorithmOIDs") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _GatekeeperConfirm[] = {        /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT,
+        offsetof(GatekeeperConfirm, rasAddress), _TransportAddress},
+       {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("authenticationMode") CHOICE, 3, 7, 8, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("algorithmOID") OID, BYTE, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _RegistrationRequest_callSignalAddress[] = {    /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+        sizeof(TransportAddress), _TransportAddress}
+       ,
+};
+
+static field_t _RegistrationRequest_rasAddress[] = {   /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+        sizeof(TransportAddress), _TransportAddress}
+       ,
+};
+
+static field_t _RegistrationRequest_terminalAlias[] = {        /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _RegistrationRequest[] = {      /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("discoveryComplete") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE,
+        offsetof(RegistrationRequest, callSignalAddress),
+        _RegistrationRequest_callSignalAddress},
+       {FNAME("rasAddress") SEQOF, SEMI, 0, 10, DECODE,
+        offsetof(RegistrationRequest, rasAddress),
+        _RegistrationRequest_rasAddress},
+       {FNAME("terminalType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType},
+       {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _RegistrationRequest_terminalAlias},
+       {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("endpointVendor") SEQ, 2, 3, 3, SKIP | EXT, 0,
+        _VendorIdentifier},
+       {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT,
+        offsetof(RegistrationRequest, timeToLive), NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("keepAlive") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT,
+        0, NULL},
+       {FNAME("additiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0,
+        NULL},
+       {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("usageReportingCapability") SEQ, 3, 4, 4, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("supportedH248Packages") SEQOF, SEMI, 0, 0, STOP | OPT, 0,
+        NULL},
+       {FNAME("callCreditCapability") SEQ, 2, 2, 2, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("capacityReportingCapability") SEQ, 0, 1, 1, STOP | EXT | OPT,
+        0, NULL},
+       {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _RegistrationConfirm_callSignalAddress[] = {    /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+        sizeof(TransportAddress), _TransportAddress}
+       ,
+};
+
+static field_t _RegistrationConfirm_terminalAlias[] = {        /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _RegistrationConfirm[] = {      /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE,
+        offsetof(RegistrationConfirm, callSignalAddress),
+        _RegistrationConfirm_callSignalAddress},
+       {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _RegistrationConfirm_terminalAlias},
+       {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL},
+       {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+       {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT,
+        offsetof(RegistrationConfirm, timeToLive), NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("preGrantedARQ") SEQ, 0, 4, 8, STOP | EXT | OPT, 0, NULL},
+       {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("supportsAdditiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0,
+        NULL},
+       {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0,
+        NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("featureServerAlias") CHOICE, 1, 2, 7, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("capacityReportingSpec") SEQ, 0, 1, 1, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _UnregistrationRequest_callSignalAddress[] = {  /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+        sizeof(TransportAddress), _TransportAddress}
+       ,
+};
+
+static field_t _UnregistrationRequest[] = {    /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE,
+        offsetof(UnregistrationRequest, callSignalAddress),
+        _UnregistrationRequest_callSignalAddress},
+       {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("reason") CHOICE, 2, 4, 5, STOP | EXT | OPT, 0, NULL},
+       {FNAME("endpointAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0,
+        NULL},
+       {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _CallModel[] = {        /* CHOICE */
+       {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+       {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+};
+
+static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _AdmissionRequest_destExtraCallInfo[] = {       /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _AdmissionRequest[] = { /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType},
+       {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel},
+       {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL},
+       {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _AdmissionRequest_destinationInfo},
+       {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(AdmissionRequest, destCallSignalAddress),
+        _TransportAddress},
+       {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+        _AdmissionRequest_destExtraCallInfo},
+       {FNAME("srcInfo") SEQOF, SEMI, 0, 0, SKIP, 0,
+        _AdmissionRequest_srcInfo},
+       {FNAME("srcCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+        offsetof(AdmissionRequest, srcCallSignalAddress), _TransportAddress},
+       {FNAME("bandWidth") INT, CONS, 0, 0, STOP, 0, NULL},
+       {FNAME("callReferenceValue") INT, WORD, 0, 0, STOP, 0, NULL},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL},
+       {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, STOP, 0, NULL},
+       {FNAME("activeMC") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("answerCall") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("callIdentifier") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+       {FNAME("srcAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("destAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL},
+       {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL},
+       {FNAME("gatewayDataRate") SEQ, 2, 3, 3, STOP | EXT | OPT, 0, NULL},
+       {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL},
+       {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL},
+       {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _AdmissionConfirm[] = { /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL},
+       {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel},
+       {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT,
+        offsetof(AdmissionConfirm, destCallSignalAddress),
+        _TransportAddress},
+       {FNAME("irrFrequency") INT, WORD, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL},
+       {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0,
+        NULL},
+       {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL},
+       {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("uuiesRequested") SEQ, 0, 9, 13, STOP | EXT, 0, NULL},
+       {FNAME("language") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT,
+        0, NULL},
+       {FNAME("useSpecifiedTransport") CHOICE, 1, 2, 2, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL},
+       {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _LocationRequest_destinationInfo[] = {  /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+};
+
+static field_t _LocationRequest[] = {  /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+       {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0,
+        _LocationRequest_destinationInfo},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("replyAddress") CHOICE, 3, 7, 7, DECODE | EXT,
+        offsetof(LocationRequest, replyAddress), _TransportAddress},
+       {FNAME("sourceInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0,
+        NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("hopCount") INT, 8, 1, 0, STOP | OPT, 0, NULL},
+       {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL},
+};
+
+static field_t _LocationConfirm[] = {  /* SEQUENCE */
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT,
+        offsetof(LocationConfirm, callSignalAddress), _TransportAddress},
+       {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT,
+        offsetof(LocationConfirm, rasAddress), _TransportAddress},
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL},
+       {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0,
+        NULL},
+       {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT,
+        0, NULL},
+       {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL},
+       {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _InfoRequestResponse_callSignalAddress[] = {    /* SEQUENCE OF */
+       {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+        sizeof(TransportAddress), _TransportAddress}
+       ,
+};
+
+static field_t _InfoRequestResponse[] = {      /* SEQUENCE */
+       {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+        _NonStandardParameter},
+       {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+       {FNAME("endpointType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType},
+       {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL},
+       {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT,
+        offsetof(InfoRequestResponse, rasAddress), _TransportAddress},
+       {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE,
+        offsetof(InfoRequestResponse, callSignalAddress),
+        _InfoRequestResponse_callSignalAddress},
+       {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("perCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+       {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL},
+       {FNAME("needResponse") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL},
+       {FNAME("irrStatus") CHOICE, 2, 4, 4, STOP | EXT | OPT, 0, NULL},
+       {FNAME("unsolicited") BOOL, FIXD, 0, 0, STOP, 0, NULL},
+       {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+};
+
+static field_t _RasMessage[] = {       /* CHOICE */
+       {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT,
+        offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest},
+       {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT,
+        offsetof(RasMessage, gatekeeperConfirm), _GatekeeperConfirm},
+       {FNAME("gatekeeperReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL},
+       {FNAME("registrationRequest") SEQ, 3, 10, 31, DECODE | EXT,
+        offsetof(RasMessage, registrationRequest), _RegistrationRequest},
+       {FNAME("registrationConfirm") SEQ, 3, 7, 24, DECODE | EXT,
+        offsetof(RasMessage, registrationConfirm), _RegistrationConfirm},
+       {FNAME("registrationReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL},
+       {FNAME("unregistrationRequest") SEQ, 3, 5, 15, DECODE | EXT,
+        offsetof(RasMessage, unregistrationRequest), _UnregistrationRequest},
+       {FNAME("unregistrationConfirm") SEQ, 1, 2, 6, STOP | EXT, 0, NULL},
+       {FNAME("unregistrationReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL},
+       {FNAME("admissionRequest") SEQ, 7, 16, 34, DECODE | EXT,
+        offsetof(RasMessage, admissionRequest), _AdmissionRequest},
+       {FNAME("admissionConfirm") SEQ, 2, 6, 27, DECODE | EXT,
+        offsetof(RasMessage, admissionConfirm), _AdmissionConfirm},
+       {FNAME("admissionReject") SEQ, 1, 3, 11, STOP | EXT, 0, NULL},
+       {FNAME("bandwidthRequest") SEQ, 2, 7, 18, STOP | EXT, 0, NULL},
+       {FNAME("bandwidthConfirm") SEQ, 1, 3, 8, STOP | EXT, 0, NULL},
+       {FNAME("bandwidthReject") SEQ, 1, 4, 9, STOP | EXT, 0, NULL},
+       {FNAME("disengageRequest") SEQ, 1, 6, 19, STOP | EXT, 0, NULL},
+       {FNAME("disengageConfirm") SEQ, 1, 2, 9, STOP | EXT, 0, NULL},
+       {FNAME("disengageReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL},
+       {FNAME("locationRequest") SEQ, 2, 5, 17, DECODE | EXT,
+        offsetof(RasMessage, locationRequest), _LocationRequest},
+       {FNAME("locationConfirm") SEQ, 1, 4, 19, DECODE | EXT,
+        offsetof(RasMessage, locationConfirm), _LocationConfirm},
+       {FNAME("locationReject") SEQ, 1, 3, 10, STOP | EXT, 0, NULL},
+       {FNAME("infoRequest") SEQ, 2, 4, 15, STOP | EXT, 0, NULL},
+       {FNAME("infoRequestResponse") SEQ, 3, 8, 16, DECODE | EXT,
+        offsetof(RasMessage, infoRequestResponse), _InfoRequestResponse},
+       {FNAME("nonStandardMessage") SEQ, 0, 2, 7, STOP | EXT, 0, NULL},
+       {FNAME("unknownMessageResponse") SEQ, 0, 1, 5, STOP | EXT, 0, NULL},
+       {FNAME("requestInProgress") SEQ, 4, 6, 6, STOP | EXT, 0, NULL},
+       {FNAME("resourcesAvailableIndicate") SEQ, 4, 9, 11, STOP | EXT, 0,
+        NULL},
+       {FNAME("resourcesAvailableConfirm") SEQ, 4, 6, 7, STOP | EXT, 0,
+        NULL},
+       {FNAME("infoRequestAck") SEQ, 4, 5, 5, STOP | EXT, 0, NULL},
+       {FNAME("infoRequestNak") SEQ, 5, 7, 7, STOP | EXT, 0, NULL},
+       {FNAME("serviceControlIndication") SEQ, 8, 10, 10, STOP | EXT, 0,
+        NULL},
+       {FNAME("serviceControlResponse") SEQ, 7, 8, 8, STOP | EXT, 0, NULL},
+};
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h
new file mode 100644 (file)
index 0000000..cc98f7a
--- /dev/null
@@ -0,0 +1,938 @@
+/* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006
+ *
+ * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ *
+ * This source code is licensed under General Public License version 2.
+ */
+
+typedef struct TransportAddress_ipAddress {    /* SEQUENCE */
+       int options;            /* No use */
+       unsigned ip;
+} TransportAddress_ipAddress;
+
+typedef struct TransportAddress {      /* CHOICE */
+       enum {
+               eTransportAddress_ipAddress,
+               eTransportAddress_ipSourceRoute,
+               eTransportAddress_ipxAddress,
+               eTransportAddress_ip6Address,
+               eTransportAddress_netBios,
+               eTransportAddress_nsap,
+               eTransportAddress_nonStandardAddress,
+       } choice;
+       union {
+               TransportAddress_ipAddress ipAddress;
+       };
+} TransportAddress;
+
+typedef struct DataProtocolCapability {        /* CHOICE */
+       enum {
+               eDataProtocolCapability_nonStandard,
+               eDataProtocolCapability_v14buffered,
+               eDataProtocolCapability_v42lapm,
+               eDataProtocolCapability_hdlcFrameTunnelling,
+               eDataProtocolCapability_h310SeparateVCStack,
+               eDataProtocolCapability_h310SingleVCStack,
+               eDataProtocolCapability_transparent,
+               eDataProtocolCapability_segmentationAndReassembly,
+               eDataProtocolCapability_hdlcFrameTunnelingwSAR,
+               eDataProtocolCapability_v120,
+               eDataProtocolCapability_separateLANStack,
+               eDataProtocolCapability_v76wCompression,
+               eDataProtocolCapability_tcp,
+               eDataProtocolCapability_udp,
+       } choice;
+} DataProtocolCapability;
+
+typedef struct DataApplicationCapability_application { /* CHOICE */
+       enum {
+               eDataApplicationCapability_application_nonStandard,
+               eDataApplicationCapability_application_t120,
+               eDataApplicationCapability_application_dsm_cc,
+               eDataApplicationCapability_application_userData,
+               eDataApplicationCapability_application_t84,
+               eDataApplicationCapability_application_t434,
+               eDataApplicationCapability_application_h224,
+               eDataApplicationCapability_application_nlpid,
+               eDataApplicationCapability_application_dsvdControl,
+               eDataApplicationCapability_application_h222DataPartitioning,
+               eDataApplicationCapability_application_t30fax,
+               eDataApplicationCapability_application_t140,
+               eDataApplicationCapability_application_t38fax,
+               eDataApplicationCapability_application_genericDataCapability,
+       } choice;
+       union {
+               DataProtocolCapability t120;
+       };
+} DataApplicationCapability_application;
+
+typedef struct DataApplicationCapability {     /* SEQUENCE */
+       int options;            /* No use */
+       DataApplicationCapability_application application;
+} DataApplicationCapability;
+
+typedef struct DataType {      /* CHOICE */
+       enum {
+               eDataType_nonStandard,
+               eDataType_nullData,
+               eDataType_videoData,
+               eDataType_audioData,
+               eDataType_data,
+               eDataType_encryptionData,
+               eDataType_h235Control,
+               eDataType_h235Media,
+               eDataType_multiplexedStream,
+       } choice;
+       union {
+               DataApplicationCapability data;
+       };
+} DataType;
+
+typedef struct UnicastAddress_iPAddress {      /* SEQUENCE */
+       int options;            /* No use */
+       unsigned network;
+} UnicastAddress_iPAddress;
+
+typedef struct UnicastAddress {        /* CHOICE */
+       enum {
+               eUnicastAddress_iPAddress,
+               eUnicastAddress_iPXAddress,
+               eUnicastAddress_iP6Address,
+               eUnicastAddress_netBios,
+               eUnicastAddress_iPSourceRouteAddress,
+               eUnicastAddress_nsap,
+               eUnicastAddress_nonStandardAddress,
+       } choice;
+       union {
+               UnicastAddress_iPAddress iPAddress;
+       };
+} UnicastAddress;
+
+typedef struct H245_TransportAddress { /* CHOICE */
+       enum {
+               eH245_TransportAddress_unicastAddress,
+               eH245_TransportAddress_multicastAddress,
+       } choice;
+       union {
+               UnicastAddress unicastAddress;
+       };
+} H245_TransportAddress;
+
+typedef struct H2250LogicalChannelParameters { /* SEQUENCE */
+       enum {
+               eH2250LogicalChannelParameters_nonStandard = (1 << 31),
+               eH2250LogicalChannelParameters_associatedSessionID =
+                   (1 << 30),
+               eH2250LogicalChannelParameters_mediaChannel = (1 << 29),
+               eH2250LogicalChannelParameters_mediaGuaranteedDelivery =
+                   (1 << 28),
+               eH2250LogicalChannelParameters_mediaControlChannel =
+                   (1 << 27),
+               eH2250LogicalChannelParameters_mediaControlGuaranteedDelivery
+                   = (1 << 26),
+               eH2250LogicalChannelParameters_silenceSuppression = (1 << 25),
+               eH2250LogicalChannelParameters_destination = (1 << 24),
+               eH2250LogicalChannelParameters_dynamicRTPPayloadType =
+                   (1 << 23),
+               eH2250LogicalChannelParameters_mediaPacketization = (1 << 22),
+               eH2250LogicalChannelParameters_transportCapability =
+                   (1 << 21),
+               eH2250LogicalChannelParameters_redundancyEncoding = (1 << 20),
+               eH2250LogicalChannelParameters_source = (1 << 19),
+       } options;
+       H245_TransportAddress mediaChannel;
+       H245_TransportAddress mediaControlChannel;
+} H2250LogicalChannelParameters;
+
+typedef struct OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters {        /* CHOICE */
+       enum {
+               eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters,
+               eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters,
+               eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters,
+               eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters,
+               eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_none,
+       } choice;
+       union {
+               H2250LogicalChannelParameters h2250LogicalChannelParameters;
+       };
+} OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters;
+
+typedef struct OpenLogicalChannel_forwardLogicalChannelParameters {    /* SEQUENCE */
+       enum {
+               eOpenLogicalChannel_forwardLogicalChannelParameters_portNumber
+                   = (1 << 31),
+               eOpenLogicalChannel_forwardLogicalChannelParameters_forwardLogicalChannelDependency
+                   = (1 << 30),
+               eOpenLogicalChannel_forwardLogicalChannelParameters_replacementFor
+                   = (1 << 29),
+       } options;
+       DataType dataType;
+       OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters
+           multiplexParameters;
+} OpenLogicalChannel_forwardLogicalChannelParameters;
+
+typedef struct OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters {        /* CHOICE */
+       enum {
+               eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters,
+               eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters,
+               eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters,
+       } choice;
+       union {
+               H2250LogicalChannelParameters h2250LogicalChannelParameters;
+       };
+} OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters;
+
+typedef struct OpenLogicalChannel_reverseLogicalChannelParameters {    /* SEQUENCE */
+       enum {
+               eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters
+                   = (1 << 31),
+               eOpenLogicalChannel_reverseLogicalChannelParameters_reverseLogicalChannelDependency
+                   = (1 << 30),
+               eOpenLogicalChannel_reverseLogicalChannelParameters_replacementFor
+                   = (1 << 29),
+       } options;
+       OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters
+           multiplexParameters;
+} OpenLogicalChannel_reverseLogicalChannelParameters;
+
+typedef struct NetworkAccessParameters_networkAddress {        /* CHOICE */
+       enum {
+               eNetworkAccessParameters_networkAddress_q2931Address,
+               eNetworkAccessParameters_networkAddress_e164Address,
+               eNetworkAccessParameters_networkAddress_localAreaAddress,
+       } choice;
+       union {
+               H245_TransportAddress localAreaAddress;
+       };
+} NetworkAccessParameters_networkAddress;
+
+typedef struct NetworkAccessParameters {       /* SEQUENCE */
+       enum {
+               eNetworkAccessParameters_distribution = (1 << 31),
+               eNetworkAccessParameters_externalReference = (1 << 30),
+               eNetworkAccessParameters_t120SetupProcedure = (1 << 29),
+       } options;
+       NetworkAccessParameters_networkAddress networkAddress;
+} NetworkAccessParameters;
+
+typedef struct OpenLogicalChannel {    /* SEQUENCE */
+       enum {
+               eOpenLogicalChannel_reverseLogicalChannelParameters =
+                   (1 << 31),
+               eOpenLogicalChannel_separateStack = (1 << 30),
+               eOpenLogicalChannel_encryptionSync = (1 << 29),
+       } options;
+       OpenLogicalChannel_forwardLogicalChannelParameters
+           forwardLogicalChannelParameters;
+       OpenLogicalChannel_reverseLogicalChannelParameters
+           reverseLogicalChannelParameters;
+       NetworkAccessParameters separateStack;
+} OpenLogicalChannel;
+
+typedef struct Setup_UUIE_fastStart {  /* SEQUENCE OF */
+       int count;
+       OpenLogicalChannel item[30];
+} Setup_UUIE_fastStart;
+
+typedef struct Setup_UUIE {    /* SEQUENCE */
+       enum {
+               eSetup_UUIE_h245Address = (1 << 31),
+               eSetup_UUIE_sourceAddress = (1 << 30),
+               eSetup_UUIE_destinationAddress = (1 << 29),
+               eSetup_UUIE_destCallSignalAddress = (1 << 28),
+               eSetup_UUIE_destExtraCallInfo = (1 << 27),
+               eSetup_UUIE_destExtraCRV = (1 << 26),
+               eSetup_UUIE_callServices = (1 << 25),
+               eSetup_UUIE_sourceCallSignalAddress = (1 << 24),
+               eSetup_UUIE_remoteExtensionAddress = (1 << 23),
+               eSetup_UUIE_callIdentifier = (1 << 22),
+               eSetup_UUIE_h245SecurityCapability = (1 << 21),
+               eSetup_UUIE_tokens = (1 << 20),
+               eSetup_UUIE_cryptoTokens = (1 << 19),
+               eSetup_UUIE_fastStart = (1 << 18),
+               eSetup_UUIE_mediaWaitForConnect = (1 << 17),
+               eSetup_UUIE_canOverlapSend = (1 << 16),
+               eSetup_UUIE_endpointIdentifier = (1 << 15),
+               eSetup_UUIE_multipleCalls = (1 << 14),
+               eSetup_UUIE_maintainConnection = (1 << 13),
+               eSetup_UUIE_connectionParameters = (1 << 12),
+               eSetup_UUIE_language = (1 << 11),
+               eSetup_UUIE_presentationIndicator = (1 << 10),
+               eSetup_UUIE_screeningIndicator = (1 << 9),
+               eSetup_UUIE_serviceControl = (1 << 8),
+               eSetup_UUIE_symmetricOperationRequired = (1 << 7),
+               eSetup_UUIE_capacity = (1 << 6),
+               eSetup_UUIE_circuitInfo = (1 << 5),
+               eSetup_UUIE_desiredProtocols = (1 << 4),
+               eSetup_UUIE_neededFeatures = (1 << 3),
+               eSetup_UUIE_desiredFeatures = (1 << 2),
+               eSetup_UUIE_supportedFeatures = (1 << 1),
+               eSetup_UUIE_parallelH245Control = (1 << 0),
+       } options;
+       TransportAddress h245Address;
+       TransportAddress destCallSignalAddress;
+       TransportAddress sourceCallSignalAddress;
+       Setup_UUIE_fastStart fastStart;
+} Setup_UUIE;
+
+typedef struct CallProceeding_UUIE_fastStart { /* SEQUENCE OF */
+       int count;
+       OpenLogicalChannel item[30];
+} CallProceeding_UUIE_fastStart;
+
+typedef struct CallProceeding_UUIE {   /* SEQUENCE */
+       enum {
+               eCallProceeding_UUIE_h245Address = (1 << 31),
+               eCallProceeding_UUIE_callIdentifier = (1 << 30),
+               eCallProceeding_UUIE_h245SecurityMode = (1 << 29),
+               eCallProceeding_UUIE_tokens = (1 << 28),
+               eCallProceeding_UUIE_cryptoTokens = (1 << 27),
+               eCallProceeding_UUIE_fastStart = (1 << 26),
+               eCallProceeding_UUIE_multipleCalls = (1 << 25),
+               eCallProceeding_UUIE_maintainConnection = (1 << 24),
+               eCallProceeding_UUIE_fastConnectRefused = (1 << 23),
+               eCallProceeding_UUIE_featureSet = (1 << 22),
+       } options;
+       TransportAddress h245Address;
+       CallProceeding_UUIE_fastStart fastStart;
+} CallProceeding_UUIE;
+
+typedef struct Connect_UUIE_fastStart {        /* SEQUENCE OF */
+       int count;
+       OpenLogicalChannel item[30];
+} Connect_UUIE_fastStart;
+
+typedef struct Connect_UUIE {  /* SEQUENCE */
+       enum {
+               eConnect_UUIE_h245Address = (1 << 31),
+               eConnect_UUIE_callIdentifier = (1 << 30),
+               eConnect_UUIE_h245SecurityMode = (1 << 29),
+               eConnect_UUIE_tokens = (1 << 28),
+               eConnect_UUIE_cryptoTokens = (1 << 27),
+               eConnect_UUIE_fastStart = (1 << 26),
+               eConnect_UUIE_multipleCalls = (1 << 25),
+               eConnect_UUIE_maintainConnection = (1 << 24),
+               eConnect_UUIE_language = (1 << 23),
+               eConnect_UUIE_connectedAddress = (1 << 22),
+               eConnect_UUIE_presentationIndicator = (1 << 21),
+               eConnect_UUIE_screeningIndicator = (1 << 20),
+               eConnect_UUIE_fastConnectRefused = (1 << 19),
+               eConnect_UUIE_serviceControl = (1 << 18),
+               eConnect_UUIE_capacity = (1 << 17),
+               eConnect_UUIE_featureSet = (1 << 16),
+       } options;
+       TransportAddress h245Address;
+       Connect_UUIE_fastStart fastStart;
+} Connect_UUIE;
+
+typedef struct Alerting_UUIE_fastStart {       /* SEQUENCE OF */
+       int count;
+       OpenLogicalChannel item[30];
+} Alerting_UUIE_fastStart;
+
+typedef struct Alerting_UUIE { /* SEQUENCE */
+       enum {
+               eAlerting_UUIE_h245Address = (1 << 31),
+               eAlerting_UUIE_callIdentifier = (1 << 30),
+               eAlerting_UUIE_h245SecurityMode = (1 << 29),
+               eAlerting_UUIE_tokens = (1 << 28),
+               eAlerting_UUIE_cryptoTokens = (1 << 27),
+               eAlerting_UUIE_fastStart = (1 << 26),
+               eAlerting_UUIE_multipleCalls = (1 << 25),
+               eAlerting_UUIE_maintainConnection = (1 << 24),
+               eAlerting_UUIE_alertingAddress = (1 << 23),
+               eAlerting_UUIE_presentationIndicator = (1 << 22),
+               eAlerting_UUIE_screeningIndicator = (1 << 21),
+               eAlerting_UUIE_fastConnectRefused = (1 << 20),
+               eAlerting_UUIE_serviceControl = (1 << 19),
+               eAlerting_UUIE_capacity = (1 << 18),
+               eAlerting_UUIE_featureSet = (1 << 17),
+       } options;
+       TransportAddress h245Address;
+       Alerting_UUIE_fastStart fastStart;
+} Alerting_UUIE;
+
+typedef struct Information_UUIE_fastStart {    /* SEQUENCE OF */
+       int count;
+       OpenLogicalChannel item[30];
+} Information_UUIE_fastStart;
+
+typedef struct Information_UUIE {      /* SEQUENCE */
+       enum {
+               eInformation_UUIE_callIdentifier = (1 << 31),
+               eInformation_UUIE_tokens = (1 << 30),
+               eInformation_UUIE_cryptoTokens = (1 << 29),
+               eInformation_UUIE_fastStart = (1 << 28),
+               eInformation_UUIE_fastConnectRefused = (1 << 27),
+               eInformation_UUIE_circuitInfo = (1 << 26),
+       } options;
+       Information_UUIE_fastStart fastStart;
+} Information_UUIE;
+
+typedef struct FacilityReason {        /* CHOICE */
+       enum {
+               eFacilityReason_routeCallToGatekeeper,
+               eFacilityReason_callForwarded,
+               eFacilityReason_routeCallToMC,
+               eFacilityReason_undefinedReason,
+               eFacilityReason_conferenceListChoice,
+               eFacilityReason_startH245,
+               eFacilityReason_noH245,
+               eFacilityReason_newTokens,
+               eFacilityReason_featureSetUpdate,
+               eFacilityReason_forwardedElements,
+               eFacilityReason_transportedInformation,
+       } choice;
+} FacilityReason;
+
+typedef struct Facility_UUIE_fastStart {       /* SEQUENCE OF */
+       int count;
+       OpenLogicalChannel item[30];
+} Facility_UUIE_fastStart;
+
+typedef struct Facility_UUIE { /* SEQUENCE */
+       enum {
+               eFacility_UUIE_alternativeAddress = (1 << 31),
+               eFacility_UUIE_alternativeAliasAddress = (1 << 30),
+               eFacility_UUIE_conferenceID = (1 << 29),
+               eFacility_UUIE_callIdentifier = (1 << 28),
+               eFacility_UUIE_destExtraCallInfo = (1 << 27),
+               eFacility_UUIE_remoteExtensionAddress = (1 << 26),
+               eFacility_UUIE_tokens = (1 << 25),
+               eFacility_UUIE_cryptoTokens = (1 << 24),
+               eFacility_UUIE_conferences = (1 << 23),
+               eFacility_UUIE_h245Address = (1 << 22),
+               eFacility_UUIE_fastStart = (1 << 21),
+               eFacility_UUIE_multipleCalls = (1 << 20),
+               eFacility_UUIE_maintainConnection = (1 << 19),
+               eFacility_UUIE_fastConnectRefused = (1 << 18),
+               eFacility_UUIE_serviceControl = (1 << 17),
+               eFacility_UUIE_circuitInfo = (1 << 16),
+               eFacility_UUIE_featureSet = (1 << 15),
+               eFacility_UUIE_destinationInfo = (1 << 14),
+               eFacility_UUIE_h245SecurityMode = (1 << 13),
+       } options;
+       FacilityReason reason;
+       TransportAddress h245Address;
+       Facility_UUIE_fastStart fastStart;
+} Facility_UUIE;
+
+typedef struct Progress_UUIE_fastStart {       /* SEQUENCE OF */
+       int count;
+       OpenLogicalChannel item[30];
+} Progress_UUIE_fastStart;
+
+typedef struct Progress_UUIE { /* SEQUENCE */
+       enum {
+               eProgress_UUIE_h245Address = (1 << 31),
+               eProgress_UUIE_h245SecurityMode = (1 << 30),
+               eProgress_UUIE_tokens = (1 << 29),
+               eProgress_UUIE_cryptoTokens = (1 << 28),
+               eProgress_UUIE_fastStart = (1 << 27),
+               eProgress_UUIE_multipleCalls = (1 << 26),
+               eProgress_UUIE_maintainConnection = (1 << 25),
+               eProgress_UUIE_fastConnectRefused = (1 << 24),
+       } options;
+       TransportAddress h245Address;
+       Progress_UUIE_fastStart fastStart;
+} Progress_UUIE;
+
+typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */
+       enum {
+               eH323_UU_PDU_h323_message_body_setup,
+               eH323_UU_PDU_h323_message_body_callProceeding,
+               eH323_UU_PDU_h323_message_body_connect,
+               eH323_UU_PDU_h323_message_body_alerting,
+               eH323_UU_PDU_h323_message_body_information,
+               eH323_UU_PDU_h323_message_body_releaseComplete,
+               eH323_UU_PDU_h323_message_body_facility,
+               eH323_UU_PDU_h323_message_body_progress,
+               eH323_UU_PDU_h323_message_body_empty,
+               eH323_UU_PDU_h323_message_body_status,
+               eH323_UU_PDU_h323_message_body_statusInquiry,
+               eH323_UU_PDU_h323_message_body_setupAcknowledge,
+               eH323_UU_PDU_h323_message_body_notify,
+       } choice;
+       union {
+               Setup_UUIE setup;
+               CallProceeding_UUIE callProceeding;
+               Connect_UUIE connect;
+               Alerting_UUIE alerting;
+               Information_UUIE information;
+               Facility_UUIE facility;
+               Progress_UUIE progress;
+       };
+} H323_UU_PDU_h323_message_body;
+
+typedef struct RequestMessage {        /* CHOICE */
+       enum {
+               eRequestMessage_nonStandard,
+               eRequestMessage_masterSlaveDetermination,
+               eRequestMessage_terminalCapabilitySet,
+               eRequestMessage_openLogicalChannel,
+               eRequestMessage_closeLogicalChannel,
+               eRequestMessage_requestChannelClose,
+               eRequestMessage_multiplexEntrySend,
+               eRequestMessage_requestMultiplexEntry,
+               eRequestMessage_requestMode,
+               eRequestMessage_roundTripDelayRequest,
+               eRequestMessage_maintenanceLoopRequest,
+               eRequestMessage_communicationModeRequest,
+               eRequestMessage_conferenceRequest,
+               eRequestMessage_multilinkRequest,
+               eRequestMessage_logicalChannelRateRequest,
+       } choice;
+       union {
+               OpenLogicalChannel openLogicalChannel;
+       };
+} RequestMessage;
+
+typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters {     /* CHOICE */
+       enum {
+               eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters,
+               eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters,
+       } choice;
+       union {
+               H2250LogicalChannelParameters h2250LogicalChannelParameters;
+       };
+} OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters;
+
+typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters { /* SEQUENCE */
+       enum {
+               eOpenLogicalChannelAck_reverseLogicalChannelParameters_portNumber
+                   = (1 << 31),
+               eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters
+                   = (1 << 30),
+               eOpenLogicalChannelAck_reverseLogicalChannelParameters_replacementFor
+                   = (1 << 29),
+       } options;
+       OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters
+           multiplexParameters;
+} OpenLogicalChannelAck_reverseLogicalChannelParameters;
+
+typedef struct H2250LogicalChannelAckParameters {      /* SEQUENCE */
+       enum {
+               eH2250LogicalChannelAckParameters_nonStandard = (1 << 31),
+               eH2250LogicalChannelAckParameters_sessionID = (1 << 30),
+               eH2250LogicalChannelAckParameters_mediaChannel = (1 << 29),
+               eH2250LogicalChannelAckParameters_mediaControlChannel =
+                   (1 << 28),
+               eH2250LogicalChannelAckParameters_dynamicRTPPayloadType =
+                   (1 << 27),
+               eH2250LogicalChannelAckParameters_flowControlToZero =
+                   (1 << 26),
+               eH2250LogicalChannelAckParameters_portNumber = (1 << 25),
+       } options;
+       H245_TransportAddress mediaChannel;
+       H245_TransportAddress mediaControlChannel;
+} H2250LogicalChannelAckParameters;
+
+typedef struct OpenLogicalChannelAck_forwardMultiplexAckParameters {   /* CHOICE */
+       enum {
+               eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters,
+       } choice;
+       union {
+               H2250LogicalChannelAckParameters
+                   h2250LogicalChannelAckParameters;
+       };
+} OpenLogicalChannelAck_forwardMultiplexAckParameters;
+
+typedef struct OpenLogicalChannelAck { /* SEQUENCE */
+       enum {
+               eOpenLogicalChannelAck_reverseLogicalChannelParameters =
+                   (1 << 31),
+               eOpenLogicalChannelAck_separateStack = (1 << 30),
+               eOpenLogicalChannelAck_forwardMultiplexAckParameters =
+                   (1 << 29),
+               eOpenLogicalChannelAck_encryptionSync = (1 << 28),
+       } options;
+       OpenLogicalChannelAck_reverseLogicalChannelParameters
+           reverseLogicalChannelParameters;
+       OpenLogicalChannelAck_forwardMultiplexAckParameters
+           forwardMultiplexAckParameters;
+} OpenLogicalChannelAck;
+
+typedef struct ResponseMessage {       /* CHOICE */
+       enum {
+               eResponseMessage_nonStandard,
+               eResponseMessage_masterSlaveDeterminationAck,
+               eResponseMessage_masterSlaveDeterminationReject,
+               eResponseMessage_terminalCapabilitySetAck,
+               eResponseMessage_terminalCapabilitySetReject,
+               eResponseMessage_openLogicalChannelAck,
+               eResponseMessage_openLogicalChannelReject,
+               eResponseMessage_closeLogicalChannelAck,
+               eResponseMessage_requestChannelCloseAck,
+               eResponseMessage_requestChannelCloseReject,
+               eResponseMessage_multiplexEntrySendAck,
+               eResponseMessage_multiplexEntrySendReject,
+               eResponseMessage_requestMultiplexEntryAck,
+               eResponseMessage_requestMultiplexEntryReject,
+               eResponseMessage_requestModeAck,
+               eResponseMessage_requestModeReject,
+               eResponseMessage_roundTripDelayResponse,
+               eResponseMessage_maintenanceLoopAck,
+               eResponseMessage_maintenanceLoopReject,
+               eResponseMessage_communicationModeResponse,
+               eResponseMessage_conferenceResponse,
+               eResponseMessage_multilinkResponse,
+               eResponseMessage_logicalChannelRateAcknowledge,
+               eResponseMessage_logicalChannelRateReject,
+       } choice;
+       union {
+               OpenLogicalChannelAck openLogicalChannelAck;
+       };
+} ResponseMessage;
+
+typedef struct MultimediaSystemControlMessage {        /* CHOICE */
+       enum {
+               eMultimediaSystemControlMessage_request,
+               eMultimediaSystemControlMessage_response,
+               eMultimediaSystemControlMessage_command,
+               eMultimediaSystemControlMessage_indication,
+       } choice;
+       union {
+               RequestMessage request;
+               ResponseMessage response;
+       };
+} MultimediaSystemControlMessage;
+
+typedef struct H323_UU_PDU_h245Control {       /* SEQUENCE OF */
+       int count;
+       MultimediaSystemControlMessage item[4];
+} H323_UU_PDU_h245Control;
+
+typedef struct H323_UU_PDU {   /* SEQUENCE */
+       enum {
+               eH323_UU_PDU_nonStandardData = (1 << 31),
+               eH323_UU_PDU_h4501SupplementaryService = (1 << 30),
+               eH323_UU_PDU_h245Tunneling = (1 << 29),
+               eH323_UU_PDU_h245Control = (1 << 28),
+               eH323_UU_PDU_nonStandardControl = (1 << 27),
+               eH323_UU_PDU_callLinkage = (1 << 26),
+               eH323_UU_PDU_tunnelledSignallingMessage = (1 << 25),
+               eH323_UU_PDU_provisionalRespToH245Tunneling = (1 << 24),
+               eH323_UU_PDU_stimulusControl = (1 << 23),
+               eH323_UU_PDU_genericData = (1 << 22),
+       } options;
+       H323_UU_PDU_h323_message_body h323_message_body;
+       H323_UU_PDU_h245Control h245Control;
+} H323_UU_PDU;
+
+typedef struct H323_UserInformation {  /* SEQUENCE */
+       enum {
+               eH323_UserInformation_user_data = (1 << 31),
+       } options;
+       H323_UU_PDU h323_uu_pdu;
+} H323_UserInformation;
+
+typedef struct GatekeeperRequest {     /* SEQUENCE */
+       enum {
+               eGatekeeperRequest_nonStandardData = (1 << 31),
+               eGatekeeperRequest_gatekeeperIdentifier = (1 << 30),
+               eGatekeeperRequest_callServices = (1 << 29),
+               eGatekeeperRequest_endpointAlias = (1 << 28),
+               eGatekeeperRequest_alternateEndpoints = (1 << 27),
+               eGatekeeperRequest_tokens = (1 << 26),
+               eGatekeeperRequest_cryptoTokens = (1 << 25),
+               eGatekeeperRequest_authenticationCapability = (1 << 24),
+               eGatekeeperRequest_algorithmOIDs = (1 << 23),
+               eGatekeeperRequest_integrity = (1 << 22),
+               eGatekeeperRequest_integrityCheckValue = (1 << 21),
+               eGatekeeperRequest_supportsAltGK = (1 << 20),
+               eGatekeeperRequest_featureSet = (1 << 19),
+               eGatekeeperRequest_genericData = (1 << 18),
+       } options;
+       TransportAddress rasAddress;
+} GatekeeperRequest;
+
+typedef struct GatekeeperConfirm {     /* SEQUENCE */
+       enum {
+               eGatekeeperConfirm_nonStandardData = (1 << 31),
+               eGatekeeperConfirm_gatekeeperIdentifier = (1 << 30),
+               eGatekeeperConfirm_alternateGatekeeper = (1 << 29),
+               eGatekeeperConfirm_authenticationMode = (1 << 28),
+               eGatekeeperConfirm_tokens = (1 << 27),
+               eGatekeeperConfirm_cryptoTokens = (1 << 26),
+               eGatekeeperConfirm_algorithmOID = (1 << 25),
+               eGatekeeperConfirm_integrity = (1 << 24),
+               eGatekeeperConfirm_integrityCheckValue = (1 << 23),
+               eGatekeeperConfirm_featureSet = (1 << 22),
+               eGatekeeperConfirm_genericData = (1 << 21),
+       } options;
+       TransportAddress rasAddress;
+} GatekeeperConfirm;
+
+typedef struct RegistrationRequest_callSignalAddress { /* SEQUENCE OF */
+       int count;
+       TransportAddress item[10];
+} RegistrationRequest_callSignalAddress;
+
+typedef struct RegistrationRequest_rasAddress {        /* SEQUENCE OF */
+       int count;
+       TransportAddress item[10];
+} RegistrationRequest_rasAddress;
+
+typedef struct RegistrationRequest {   /* SEQUENCE */
+       enum {
+               eRegistrationRequest_nonStandardData = (1 << 31),
+               eRegistrationRequest_terminalAlias = (1 << 30),
+               eRegistrationRequest_gatekeeperIdentifier = (1 << 29),
+               eRegistrationRequest_alternateEndpoints = (1 << 28),
+               eRegistrationRequest_timeToLive = (1 << 27),
+               eRegistrationRequest_tokens = (1 << 26),
+               eRegistrationRequest_cryptoTokens = (1 << 25),
+               eRegistrationRequest_integrityCheckValue = (1 << 24),
+               eRegistrationRequest_keepAlive = (1 << 23),
+               eRegistrationRequest_endpointIdentifier = (1 << 22),
+               eRegistrationRequest_willSupplyUUIEs = (1 << 21),
+               eRegistrationRequest_maintainConnection = (1 << 20),
+               eRegistrationRequest_alternateTransportAddresses = (1 << 19),
+               eRegistrationRequest_additiveRegistration = (1 << 18),
+               eRegistrationRequest_terminalAliasPattern = (1 << 17),
+               eRegistrationRequest_supportsAltGK = (1 << 16),
+               eRegistrationRequest_usageReportingCapability = (1 << 15),
+               eRegistrationRequest_multipleCalls = (1 << 14),
+               eRegistrationRequest_supportedH248Packages = (1 << 13),
+               eRegistrationRequest_callCreditCapability = (1 << 12),
+               eRegistrationRequest_capacityReportingCapability = (1 << 11),
+               eRegistrationRequest_capacity = (1 << 10),
+               eRegistrationRequest_featureSet = (1 << 9),
+               eRegistrationRequest_genericData = (1 << 8),
+       } options;
+       RegistrationRequest_callSignalAddress callSignalAddress;
+       RegistrationRequest_rasAddress rasAddress;
+       unsigned timeToLive;
+} RegistrationRequest;
+
+typedef struct RegistrationConfirm_callSignalAddress { /* SEQUENCE OF */
+       int count;
+       TransportAddress item[10];
+} RegistrationConfirm_callSignalAddress;
+
+typedef struct RegistrationConfirm {   /* SEQUENCE */
+       enum {
+               eRegistrationConfirm_nonStandardData = (1 << 31),
+               eRegistrationConfirm_terminalAlias = (1 << 30),
+               eRegistrationConfirm_gatekeeperIdentifier = (1 << 29),
+               eRegistrationConfirm_alternateGatekeeper = (1 << 28),
+               eRegistrationConfirm_timeToLive = (1 << 27),
+               eRegistrationConfirm_tokens = (1 << 26),
+               eRegistrationConfirm_cryptoTokens = (1 << 25),
+               eRegistrationConfirm_integrityCheckValue = (1 << 24),
+               eRegistrationConfirm_willRespondToIRR = (1 << 23),
+               eRegistrationConfirm_preGrantedARQ = (1 << 22),
+               eRegistrationConfirm_maintainConnection = (1 << 21),
+               eRegistrationConfirm_serviceControl = (1 << 20),
+               eRegistrationConfirm_supportsAdditiveRegistration = (1 << 19),
+               eRegistrationConfirm_terminalAliasPattern = (1 << 18),
+               eRegistrationConfirm_supportedPrefixes = (1 << 17),
+               eRegistrationConfirm_usageSpec = (1 << 16),
+               eRegistrationConfirm_featureServerAlias = (1 << 15),
+               eRegistrationConfirm_capacityReportingSpec = (1 << 14),
+               eRegistrationConfirm_featureSet = (1 << 13),
+               eRegistrationConfirm_genericData = (1 << 12),
+       } options;
+       RegistrationConfirm_callSignalAddress callSignalAddress;
+       unsigned timeToLive;
+} RegistrationConfirm;
+
+typedef struct UnregistrationRequest_callSignalAddress {       /* SEQUENCE OF */
+       int count;
+       TransportAddress item[10];
+} UnregistrationRequest_callSignalAddress;
+
+typedef struct UnregistrationRequest { /* SEQUENCE */
+       enum {
+               eUnregistrationRequest_endpointAlias = (1 << 31),
+               eUnregistrationRequest_nonStandardData = (1 << 30),
+               eUnregistrationRequest_endpointIdentifier = (1 << 29),
+               eUnregistrationRequest_alternateEndpoints = (1 << 28),
+               eUnregistrationRequest_gatekeeperIdentifier = (1 << 27),
+               eUnregistrationRequest_tokens = (1 << 26),
+               eUnregistrationRequest_cryptoTokens = (1 << 25),
+               eUnregistrationRequest_integrityCheckValue = (1 << 24),
+               eUnregistrationRequest_reason = (1 << 23),
+               eUnregistrationRequest_endpointAliasPattern = (1 << 22),
+               eUnregistrationRequest_supportedPrefixes = (1 << 21),
+               eUnregistrationRequest_alternateGatekeeper = (1 << 20),
+               eUnregistrationRequest_genericData = (1 << 19),
+       } options;
+       UnregistrationRequest_callSignalAddress callSignalAddress;
+} UnregistrationRequest;
+
+typedef struct AdmissionRequest {      /* SEQUENCE */
+       enum {
+               eAdmissionRequest_callModel = (1 << 31),
+               eAdmissionRequest_destinationInfo = (1 << 30),
+               eAdmissionRequest_destCallSignalAddress = (1 << 29),
+               eAdmissionRequest_destExtraCallInfo = (1 << 28),
+               eAdmissionRequest_srcCallSignalAddress = (1 << 27),
+               eAdmissionRequest_nonStandardData = (1 << 26),
+               eAdmissionRequest_callServices = (1 << 25),
+               eAdmissionRequest_canMapAlias = (1 << 24),
+               eAdmissionRequest_callIdentifier = (1 << 23),
+               eAdmissionRequest_srcAlternatives = (1 << 22),
+               eAdmissionRequest_destAlternatives = (1 << 21),
+               eAdmissionRequest_gatekeeperIdentifier = (1 << 20),
+               eAdmissionRequest_tokens = (1 << 19),
+               eAdmissionRequest_cryptoTokens = (1 << 18),
+               eAdmissionRequest_integrityCheckValue = (1 << 17),
+               eAdmissionRequest_transportQOS = (1 << 16),
+               eAdmissionRequest_willSupplyUUIEs = (1 << 15),
+               eAdmissionRequest_callLinkage = (1 << 14),
+               eAdmissionRequest_gatewayDataRate = (1 << 13),
+               eAdmissionRequest_capacity = (1 << 12),
+               eAdmissionRequest_circuitInfo = (1 << 11),
+               eAdmissionRequest_desiredProtocols = (1 << 10),
+               eAdmissionRequest_desiredTunnelledProtocol = (1 << 9),
+               eAdmissionRequest_featureSet = (1 << 8),
+               eAdmissionRequest_genericData = (1 << 7),
+       } options;
+       TransportAddress destCallSignalAddress;
+       TransportAddress srcCallSignalAddress;
+} AdmissionRequest;
+
+typedef struct AdmissionConfirm {      /* SEQUENCE */
+       enum {
+               eAdmissionConfirm_irrFrequency = (1 << 31),
+               eAdmissionConfirm_nonStandardData = (1 << 30),
+               eAdmissionConfirm_destinationInfo = (1 << 29),
+               eAdmissionConfirm_destExtraCallInfo = (1 << 28),
+               eAdmissionConfirm_destinationType = (1 << 27),
+               eAdmissionConfirm_remoteExtensionAddress = (1 << 26),
+               eAdmissionConfirm_alternateEndpoints = (1 << 25),
+               eAdmissionConfirm_tokens = (1 << 24),
+               eAdmissionConfirm_cryptoTokens = (1 << 23),
+               eAdmissionConfirm_integrityCheckValue = (1 << 22),
+               eAdmissionConfirm_transportQOS = (1 << 21),
+               eAdmissionConfirm_willRespondToIRR = (1 << 20),
+               eAdmissionConfirm_uuiesRequested = (1 << 19),
+               eAdmissionConfirm_language = (1 << 18),
+               eAdmissionConfirm_alternateTransportAddresses = (1 << 17),
+               eAdmissionConfirm_useSpecifiedTransport = (1 << 16),
+               eAdmissionConfirm_circuitInfo = (1 << 15),
+               eAdmissionConfirm_usageSpec = (1 << 14),
+               eAdmissionConfirm_supportedProtocols = (1 << 13),
+               eAdmissionConfirm_serviceControl = (1 << 12),
+               eAdmissionConfirm_multipleCalls = (1 << 11),
+               eAdmissionConfirm_featureSet = (1 << 10),
+               eAdmissionConfirm_genericData = (1 << 9),
+       } options;
+       TransportAddress destCallSignalAddress;
+} AdmissionConfirm;
+
+typedef struct LocationRequest {       /* SEQUENCE */
+       enum {
+               eLocationRequest_endpointIdentifier = (1 << 31),
+               eLocationRequest_nonStandardData = (1 << 30),
+               eLocationRequest_sourceInfo = (1 << 29),
+               eLocationRequest_canMapAlias = (1 << 28),
+               eLocationRequest_gatekeeperIdentifier = (1 << 27),
+               eLocationRequest_tokens = (1 << 26),
+               eLocationRequest_cryptoTokens = (1 << 25),
+               eLocationRequest_integrityCheckValue = (1 << 24),
+               eLocationRequest_desiredProtocols = (1 << 23),
+               eLocationRequest_desiredTunnelledProtocol = (1 << 22),
+               eLocationRequest_featureSet = (1 << 21),
+               eLocationRequest_genericData = (1 << 20),
+               eLocationRequest_hopCount = (1 << 19),
+               eLocationRequest_circuitInfo = (1 << 18),
+       } options;
+       TransportAddress replyAddress;
+} LocationRequest;
+
+typedef struct LocationConfirm {       /* SEQUENCE */
+       enum {
+               eLocationConfirm_nonStandardData = (1 << 31),
+               eLocationConfirm_destinationInfo = (1 << 30),
+               eLocationConfirm_destExtraCallInfo = (1 << 29),
+               eLocationConfirm_destinationType = (1 << 28),
+               eLocationConfirm_remoteExtensionAddress = (1 << 27),
+               eLocationConfirm_alternateEndpoints = (1 << 26),
+               eLocationConfirm_tokens = (1 << 25),
+               eLocationConfirm_cryptoTokens = (1 << 24),
+               eLocationConfirm_integrityCheckValue = (1 << 23),
+               eLocationConfirm_alternateTransportAddresses = (1 << 22),
+               eLocationConfirm_supportedProtocols = (1 << 21),
+               eLocationConfirm_multipleCalls = (1 << 20),
+               eLocationConfirm_featureSet = (1 << 19),
+               eLocationConfirm_genericData = (1 << 18),
+               eLocationConfirm_circuitInfo = (1 << 17),
+               eLocationConfirm_serviceControl = (1 << 16),
+       } options;
+       TransportAddress callSignalAddress;
+       TransportAddress rasAddress;
+} LocationConfirm;
+
+typedef struct InfoRequestResponse_callSignalAddress { /* SEQUENCE OF */
+       int count;
+       TransportAddress item[10];
+} InfoRequestResponse_callSignalAddress;
+
+typedef struct InfoRequestResponse {   /* SEQUENCE */
+       enum {
+               eInfoRequestResponse_nonStandardData = (1 << 31),
+               eInfoRequestResponse_endpointAlias = (1 << 30),
+               eInfoRequestResponse_perCallInfo = (1 << 29),
+               eInfoRequestResponse_tokens = (1 << 28),
+               eInfoRequestResponse_cryptoTokens = (1 << 27),
+               eInfoRequestResponse_integrityCheckValue = (1 << 26),
+               eInfoRequestResponse_needResponse = (1 << 25),
+               eInfoRequestResponse_capacity = (1 << 24),
+               eInfoRequestResponse_irrStatus = (1 << 23),
+               eInfoRequestResponse_unsolicited = (1 << 22),
+               eInfoRequestResponse_genericData = (1 << 21),
+       } options;
+       TransportAddress rasAddress;
+       InfoRequestResponse_callSignalAddress callSignalAddress;
+} InfoRequestResponse;
+
+typedef struct RasMessage {    /* CHOICE */
+       enum {
+               eRasMessage_gatekeeperRequest,
+               eRasMessage_gatekeeperConfirm,
+               eRasMessage_gatekeeperReject,
+               eRasMessage_registrationRequest,
+               eRasMessage_registrationConfirm,
+               eRasMessage_registrationReject,
+               eRasMessage_unregistrationRequest,
+               eRasMessage_unregistrationConfirm,
+               eRasMessage_unregistrationReject,
+               eRasMessage_admissionRequest,
+               eRasMessage_admissionConfirm,
+               eRasMessage_admissionReject,
+               eRasMessage_bandwidthRequest,
+               eRasMessage_bandwidthConfirm,
+               eRasMessage_bandwidthReject,
+               eRasMessage_disengageRequest,
+               eRasMessage_disengageConfirm,
+               eRasMessage_disengageReject,
+               eRasMessage_locationRequest,
+               eRasMessage_locationConfirm,
+               eRasMessage_locationReject,
+               eRasMessage_infoRequest,
+               eRasMessage_infoRequestResponse,
+               eRasMessage_nonStandardMessage,
+               eRasMessage_unknownMessageResponse,
+               eRasMessage_requestInProgress,
+               eRasMessage_resourcesAvailableIndicate,
+               eRasMessage_resourcesAvailableConfirm,
+               eRasMessage_infoRequestAck,
+               eRasMessage_infoRequestNak,
+               eRasMessage_serviceControlIndication,
+               eRasMessage_serviceControlResponse,
+       } choice;
+       union {
+               GatekeeperRequest gatekeeperRequest;
+               GatekeeperConfirm gatekeeperConfirm;
+               RegistrationRequest registrationRequest;
+               RegistrationConfirm registrationConfirm;
+               UnregistrationRequest unregistrationRequest;
+               AdmissionRequest admissionRequest;
+               AdmissionConfirm admissionConfirm;
+               LocationRequest locationRequest;
+               LocationConfirm locationConfirm;
+               InfoRequestResponse infoRequestResponse;
+       };
+} RasMessage;
index e0b5926..5ce2e3f 100644 (file)
@@ -327,9 +327,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
                group = NFNLGRP_CONNTRACK_UPDATE;
        } else 
                return NOTIFY_DONE;
-       
-  /* FIXME: Check if there are any listeners before, don't hurt performance */
-       
+
+       if (!nfnetlink_has_listeners(group))
+               return NOTIFY_DONE;
+
        skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
        if (!skb)
                return NOTIFY_DONE;
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c
new file mode 100644 (file)
index 0000000..a0bc883
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * H.323 extension for NAT alteration.
+ *
+ * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ *
+ * This source code is licensed under General Public License version 2.
+ *
+ * Based on the 'brute force' H.323 NAT module by
+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * Changes:
+ *     2006-02-01 - initial version 0.1
+ *
+ *     2006-02-20 - version 0.2
+ *       1. Changed source format to follow kernel conventions
+ *       2. Deleted some unnecessary structures
+ *       3. Minor fixes
+ *
+ *     2006-03-10 - version 0.3
+ *       1. Added support for multiple TPKTs in one packet (suggested by
+ *          Patrick McHardy)
+ *       2. Added support for non-linear skb (based on Patrick McHardy's patch)
+ *       3. Eliminated unnecessary return code
+ *
+ *     2006-03-15 - version 0.4
+ *       1. Added support for T.120 channels
+ *       2. Added parameter gkrouted_only (suggested by Patrick McHardy)
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/moduleparam.h>
+#include <net/tcp.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+
+#include "ip_conntrack_helper_h323_asn1.h"
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+extern int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
+                        u_int32_t * ip, u_int16_t * port);
+extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
+                        u_int32_t * ip, u_int16_t * port);
+extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
+                                    struct ip_conntrack_expect *this);
+extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
+                                    struct ip_conntrack_expect *this);
+extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
+                                 unsigned char **data, int dataoff,
+                                 H245_TransportAddress * addr,
+                                 u_int32_t ip, u_int16_t port);
+extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
+                                 unsigned char **data, int dataoff,
+                                 TransportAddress * addr,
+                                 u_int32_t ip, u_int16_t port);
+extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
+                                struct ip_conntrack * ct,
+                                enum ip_conntrack_info ctinfo,
+                                unsigned char **data,
+                                TransportAddress * addr, int count);
+extern int (*set_ras_addr_hook) (struct sk_buff ** pskb,
+                                struct ip_conntrack * ct,
+                                enum ip_conntrack_info ctinfo,
+                                unsigned char **data,
+                                TransportAddress * addr, int count);
+extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
+                                struct ip_conntrack * ct,
+                                enum ip_conntrack_info ctinfo,
+                                unsigned char **data, int dataoff,
+                                H245_TransportAddress * addr,
+                                u_int16_t port, u_int16_t rtp_port,
+                                struct ip_conntrack_expect * rtp_exp,
+                                struct ip_conntrack_expect * rtcp_exp);
+extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+                            enum ip_conntrack_info ctinfo,
+                            unsigned char **data, int dataoff,
+                            H245_TransportAddress * addr, u_int16_t port,
+                            struct ip_conntrack_expect * exp);
+extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+                            enum ip_conntrack_info ctinfo,
+                            unsigned char **data, int dataoff,
+                            TransportAddress * addr, u_int16_t port,
+                            struct ip_conntrack_expect * exp);
+extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+                            enum ip_conntrack_info ctinfo,
+                            unsigned char **data, TransportAddress * addr,
+                            int idx, u_int16_t port,
+                            struct ip_conntrack_expect * exp);
+
+
+/****************************************************************************/
+static int set_addr(struct sk_buff **pskb,
+                   unsigned char **data, int dataoff,
+                   unsigned int addroff, u_int32_t ip, u_int16_t port)
+{
+       enum ip_conntrack_info ctinfo;
+       struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
+       struct {
+               u_int32_t ip;
+               u_int16_t port;
+       } __attribute__ ((__packed__)) buf;
+       struct tcphdr _tcph, *th;
+
+       buf.ip = ip;
+       buf.port = htons(port);
+       addroff += dataoff;
+
+       if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
+               if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+                                             addroff, sizeof(buf),
+                                             (char *) &buf, sizeof(buf))) {
+                       if (net_ratelimit())
+                               printk("ip_nat_h323: ip_nat_mangle_tcp_packet"
+                                      " error\n");
+                       return -1;
+               }
+
+               /* Relocate data pointer */
+               th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
+                                       sizeof(_tcph), &_tcph);
+               if (th == NULL)
+                       return -1;
+               *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
+                   th->doff * 4 + dataoff;
+       } else {
+               if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
+                                             addroff, sizeof(buf),
+                                             (char *) &buf, sizeof(buf))) {
+                       if (net_ratelimit())
+                               printk("ip_nat_h323: ip_nat_mangle_udp_packet"
+                                      " error\n");
+                       return -1;
+               }
+               /* ip_nat_mangle_udp_packet uses skb_make_writable() to copy
+                * or pull everything in a linear buffer, so we can safely
+                * use the skb pointers now */
+               *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
+                   sizeof(struct udphdr);
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int set_h225_addr(struct sk_buff **pskb,
+                        unsigned char **data, int dataoff,
+                        TransportAddress * addr,
+                        u_int32_t ip, u_int16_t port)
+{
+       return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port);
+}
+
+/****************************************************************************/
+static int set_h245_addr(struct sk_buff **pskb,
+                        unsigned char **data, int dataoff,
+                        H245_TransportAddress * addr,
+                        u_int32_t ip, u_int16_t port)
+{
+       return set_addr(pskb, data, dataoff,
+                       addr->unicastAddress.iPAddress.network, ip, port);
+}
+
+/****************************************************************************/
+static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
+                       enum ip_conntrack_info ctinfo,
+                       unsigned char **data,
+                       TransportAddress * addr, int count)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       int i;
+       u_int32_t ip;
+       u_int16_t port;
+
+       for (i = 0; i < count; i++) {
+               if (get_h225_addr(*data, &addr[i], &ip, &port)) {
+                       if (ip == ct->tuplehash[dir].tuple.src.ip &&
+                           port == info->sig_port[dir]) {
+                               /* GW->GK */
+
+                               /* Fix for Gnomemeeting */
+                               if (i > 0 &&
+                                   get_h225_addr(*data, &addr[0],
+                                                 &ip, &port) &&
+                                   (ntohl(ip) & 0xff000000) == 0x7f000000)
+                                       i = 0;
+
+                               DEBUGP
+                                   ("ip_nat_ras: set signal address "
+                                    "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                                    NIPQUAD(ip), port,
+                                    NIPQUAD(ct->tuplehash[!dir].tuple.dst.
+                                            ip), info->sig_port[!dir]);
+                               return set_h225_addr(pskb, data, 0, &addr[i],
+                                                    ct->tuplehash[!dir].
+                                                    tuple.dst.ip,
+                                                    info->sig_port[!dir]);
+                       } else if (ip == ct->tuplehash[dir].tuple.dst.ip &&
+                                  port == info->sig_port[dir]) {
+                               /* GK->GW */
+                               DEBUGP
+                                   ("ip_nat_ras: set signal address "
+                                    "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                                    NIPQUAD(ip), port,
+                                    NIPQUAD(ct->tuplehash[!dir].tuple.src.
+                                            ip), info->sig_port[!dir]);
+                               return set_h225_addr(pskb, data, 0, &addr[i],
+                                                    ct->tuplehash[!dir].
+                                                    tuple.src.ip,
+                                                    info->sig_port[!dir]);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
+                       enum ip_conntrack_info ctinfo,
+                       unsigned char **data,
+                       TransportAddress * addr, int count)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       int i;
+       u_int32_t ip;
+       u_int16_t port;
+
+       for (i = 0; i < count; i++) {
+               if (get_h225_addr(*data, &addr[i], &ip, &port) &&
+                   ip == ct->tuplehash[dir].tuple.src.ip &&
+                   port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) {
+                       DEBUGP("ip_nat_ras: set rasAddress "
+                              "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+                              NIPQUAD(ip), port,
+                              NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
+                              ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
+                                    port));
+                       return set_h225_addr(pskb, data, 0, &addr[i],
+                                            ct->tuplehash[!dir].tuple.dst.ip,
+                                            ntohs(ct->tuplehash[!dir].tuple.
+                                                  dst.u.udp.port));
+               }
+       }
+
+       return 0;
+}
+
+/****************************************************************************/
+static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
+                       enum ip_conntrack_info ctinfo,
+                       unsigned char **data, int dataoff,
+                       H245_TransportAddress * addr,
+                       u_int16_t port, u_int16_t rtp_port,
+                       struct ip_conntrack_expect *rtp_exp,
+                       struct ip_conntrack_expect *rtcp_exp)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       int i;
+       u_int16_t nated_port;
+
+       /* Set expectations for NAT */
+       rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
+       rtp_exp->expectfn = ip_nat_follow_master;
+       rtp_exp->dir = !dir;
+       rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
+       rtcp_exp->expectfn = ip_nat_follow_master;
+       rtcp_exp->dir = !dir;
+
+       /* Lookup existing expects */
+       for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
+               if (info->rtp_port[i][dir] == rtp_port) {
+                       /* Expected */
+
+                       /* Use allocated ports first. This will refresh
+                        * the expects */
+                       rtp_exp->tuple.dst.u.udp.port =
+                           htons(info->rtp_port[i][dir]);
+                       rtcp_exp->tuple.dst.u.udp.port =
+                           htons(info->rtp_port[i][dir] + 1);
+                       break;
+               } else if (info->rtp_port[i][dir] == 0) {
+                       /* Not expected */
+                       break;
+               }
+       }
+
+       /* Run out of expectations */
+       if (i >= H323_RTP_CHANNEL_MAX) {
+               if (net_ratelimit())
+                       printk("ip_nat_h323: out of expectations\n");
+               return 0;
+       }
+
+       /* Try to get a pair of ports. */
+       for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
+            nated_port != 0; nated_port += 2) {
+               rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
+               if (ip_conntrack_expect_related(rtp_exp) == 0) {
+                       rtcp_exp->tuple.dst.u.udp.port =
+                           htons(nated_port + 1);
+                       if (ip_conntrack_expect_related(rtcp_exp) == 0)
+                               break;
+                       ip_conntrack_unexpect_related(rtp_exp);
+               }
+       }
+
+       if (nated_port == 0) {  /* No port available */
+               if (net_ratelimit())
+                       printk("ip_nat_h323: out of RTP ports\n");
+               return 0;
+       }
+
+       /* Modify signal */
+       if (set_h245_addr(pskb, data, dataoff, addr,
+                         ct->tuplehash[!dir].tuple.dst.ip,
+                         (port & 1) ? nated_port + 1 : nated_port) == 0) {
+               /* Save ports */
+               info->rtp_port[i][dir] = rtp_port;
+               info->rtp_port[i][!dir] = nated_port;
+       } else {
+               ip_conntrack_unexpect_related(rtp_exp);
+               ip_conntrack_unexpect_related(rtcp_exp);
+               return -1;
+       }
+
+       /* Success */
+       DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+              NIPQUAD(rtp_exp->tuple.src.ip),
+              ntohs(rtp_exp->tuple.src.u.udp.port),
+              NIPQUAD(rtp_exp->tuple.dst.ip),
+              ntohs(rtp_exp->tuple.dst.u.udp.port));
+       DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+              NIPQUAD(rtcp_exp->tuple.src.ip),
+              ntohs(rtcp_exp->tuple.src.u.udp.port),
+              NIPQUAD(rtcp_exp->tuple.dst.ip),
+              ntohs(rtcp_exp->tuple.dst.u.udp.port));
+
+       return 0;
+}
+
+/****************************************************************************/
+static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct,
+                   enum ip_conntrack_info ctinfo,
+                   unsigned char **data, int dataoff,
+                   H245_TransportAddress * addr, u_int16_t port,
+                   struct ip_conntrack_expect *exp)
+{
+       int dir = CTINFO2DIR(ctinfo);
+       u_int16_t nated_port = port;
+
+       /* Set expectations for NAT */
+       exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+       exp->expectfn = ip_nat_follow_master;
+       exp->dir = !dir;
+
+       /* Try to get same port: if not, try to change it. */
+       for (; nated_port != 0; nated_port++) {
+               exp->tuple.dst.u.tcp.port = htons(nated_port);
+               if (ip_conntrack_expect_related(exp) == 0)
+                       break;
+       }
+
+       if (nated_port == 0) {  /* No port available */
+               if (net_ratelimit())
+                       printk("ip_nat_h323: out of TCP ports\n");
+               return 0;
+       }
+
+       /* Modify signal */
+       if (set_h245_addr(pskb, data, dataoff, addr,
+                         ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) {
+               ip_conntrack_unexpect_related(exp);
+               return -1;
+       }
+
+       DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+              NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
+              NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
+
+       return 0;
+}
+
+/****************************************************************************
+ * This conntrack expect function replaces ip_conntrack_h245_expect()
+ * which was set by ip_conntrack_helper_h323.c. It calls both
+ * ip_nat_follow_master() and ip_conntrack_h245_expect()
+ ****************************************************************************/
+static void ip_nat_h245_expect(struct ip_conntrack *new,
+                              struct ip_conntrack_expect *this)
+{
+       ip_nat_follow_master(new, this);
+       ip_conntrack_h245_expect(new, this);
+}
+
+/****************************************************************************/
+static int nat_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
+                   enum ip_conntrack_info ctinfo,
+                   unsigned char **data, int dataoff,
+                   TransportAddress * addr, u_int16_t port,
+                   struct ip_conntrack_expect *exp)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       u_int16_t nated_port = port;
+
+       /* Set expectations for NAT */
+       exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+       exp->expectfn = ip_nat_h245_expect;
+       exp->dir = !dir;
+
+       /* Check existing expects */
+       if (info->sig_port[dir] == port)
+               nated_port = info->sig_port[!dir];
+
+       /* Try to get same port: if not, try to change it. */
+       for (; nated_port != 0; nated_port++) {
+               exp->tuple.dst.u.tcp.port = htons(nated_port);
+               if (ip_conntrack_expect_related(exp) == 0)
+                       break;
+       }
+
+       if (nated_port == 0) {  /* No port available */
+               if (net_ratelimit())
+                       printk("ip_nat_q931: out of TCP ports\n");
+               return 0;
+       }
+
+       /* Modify signal */
+       if (set_h225_addr(pskb, data, dataoff, addr,
+                         ct->tuplehash[!dir].tuple.dst.ip,
+                         nated_port) == 0) {
+               /* Save ports */
+               info->sig_port[dir] = port;
+               info->sig_port[!dir] = nated_port;
+       } else {
+               ip_conntrack_unexpect_related(exp);
+               return -1;
+       }
+
+       DEBUGP("ip_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+              NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
+              NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
+
+       return 0;
+}
+
+/****************************************************************************
+ * This conntrack expect function replaces ip_conntrack_q931_expect()
+ * which was set by ip_conntrack_helper_h323.c.
+ ****************************************************************************/
+static void ip_nat_q931_expect(struct ip_conntrack *new,
+                              struct ip_conntrack_expect *this)
+{
+       struct ip_nat_range range;
+
+       if (this->tuple.src.ip != 0) {  /* Only accept calls from GK */
+               ip_nat_follow_master(new, this);
+               goto out;
+       }
+
+       /* This must be a fresh one. */
+       BUG_ON(new->status & IPS_NAT_DONE_MASK);
+
+       /* Change src to where master sends to */
+       range.flags = IP_NAT_RANGE_MAP_IPS;
+       range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip;
+
+       /* hook doesn't matter, but it has to do source manip */
+       ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
+
+       /* For DST manip, map port here to where it's expected. */
+       range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+       range.min = range.max = this->saved_proto;
+       range.min_ip = range.max_ip =
+           new->master->tuplehash[!this->dir].tuple.src.ip;
+
+       /* hook doesn't matter, but it has to do destination manip */
+       ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
+
+      out:
+       ip_conntrack_q931_expect(new, this);
+}
+
+/****************************************************************************/
+static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
+                   enum ip_conntrack_info ctinfo,
+                   unsigned char **data, TransportAddress * addr, int idx,
+                   u_int16_t port, struct ip_conntrack_expect *exp)
+{
+       struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
+       int dir = CTINFO2DIR(ctinfo);
+       u_int16_t nated_port = port;
+       u_int32_t ip;
+
+       /* Set expectations for NAT */
+       exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+       exp->expectfn = ip_nat_q931_expect;
+       exp->dir = !dir;
+
+       /* Check existing expects */
+       if (info->sig_port[dir] == port)
+               nated_port = info->sig_port[!dir];
+
+       /* Try to get same port: if not, try to change it. */
+       for (; nated_port != 0; nated_port++) {
+               exp->tuple.dst.u.tcp.port = htons(nated_port);
+               if (ip_conntrack_expect_related(exp) == 0)
+                       break;
+       }
+
+       if (nated_port == 0) {  /* No port available */
+               if (net_ratelimit())
+                       printk("ip_nat_ras: out of TCP ports\n");
+               return 0;
+       }
+
+       /* Modify signal */
+       if (set_h225_addr(pskb, data, 0, &addr[idx],
+                         ct->tuplehash[!dir].tuple.dst.ip,
+                         nated_port) == 0) {
+               /* Save ports */
+               info->sig_port[dir] = port;
+               info->sig_port[!dir] = nated_port;
+
+               /* Fix for Gnomemeeting */
+               if (idx > 0 &&
+                   get_h225_addr(*data, &addr[0], &ip, &port) &&
+                   (ntohl(ip) & 0xff000000) == 0x7f000000) {
+                       set_h225_addr_hook(pskb, data, 0, &addr[0],
+                                          ct->tuplehash[!dir].tuple.dst.ip,
+                                          info->sig_port[!dir]);
+               }
+       } else {
+               ip_conntrack_unexpect_related(exp);
+               return -1;
+       }
+
+       /* Success */
+       DEBUGP("ip_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+              NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
+              NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
+
+       return 0;
+}
+
+/****************************************************************************/
+static int __init init(void)
+{
+       BUG_ON(set_h245_addr_hook != NULL);
+       BUG_ON(set_h225_addr_hook != NULL);
+       BUG_ON(set_sig_addr_hook != NULL);
+       BUG_ON(set_ras_addr_hook != NULL);
+       BUG_ON(nat_rtp_rtcp_hook != NULL);
+       BUG_ON(nat_t120_hook != NULL);
+       BUG_ON(nat_h245_hook != NULL);
+       BUG_ON(nat_q931_hook != NULL);
+
+       set_h245_addr_hook = set_h245_addr;
+       set_h225_addr_hook = set_h225_addr;
+       set_sig_addr_hook = set_sig_addr;
+       set_ras_addr_hook = set_ras_addr;
+       nat_rtp_rtcp_hook = nat_rtp_rtcp;
+       nat_t120_hook = nat_t120;
+       nat_h245_hook = nat_h245;
+       nat_q931_hook = nat_q931;
+
+       DEBUGP("ip_nat_h323: init success\n");
+       return 0;
+}
+
+/****************************************************************************/
+static void __exit fini(void)
+{
+       set_h245_addr_hook = NULL;
+       set_h225_addr_hook = NULL;
+       set_sig_addr_hook = NULL;
+       set_ras_addr_hook = NULL;
+       nat_rtp_rtcp_hook = NULL;
+       nat_t120_hook = NULL;
+       nat_h245_hook = NULL;
+       nat_q931_hook = NULL;
+       synchronize_net();
+}
+
+/****************************************************************************/
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
+MODULE_DESCRIPTION("H.323 NAT helper");
+MODULE_LICENSE("GPL");
index ac00489..b9c016c 100644 (file)
@@ -52,6 +52,8 @@
 
 #define IP_NAT_PPTP_VERSION "3.0"
 
+#define REQ_CID(req, off)              (*(u_int16_t *)((char *)(req) + (off)))
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
@@ -198,7 +200,7 @@ pptp_outbound_pkt(struct sk_buff **pskb,
        /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass
         * down to here */
        DEBUGP("altering call id from 0x%04x to 0x%04x\n",
-               ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_callid));
+               ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
 
        /* mangle packet */
        if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
@@ -342,7 +344,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
 
        /* mangle packet */
        DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
-               ntohs(*(u_int16_t *)pptpReq + pcid_off), ntohs(new_pcid));
+               ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
 
        if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
                                     pcid_off + sizeof(struct pptp_pkt_hdr) +
@@ -353,7 +355,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
 
        if (new_cid) {
                DEBUGP("altering call id from 0x%04x to 0x%04x\n",
-                       ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_cid));
+                       ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_cid));
                if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
                                             cid_off + sizeof(struct pptp_pkt_hdr) +
                                             sizeof(struct PptpControlHeader),
index 1de8628..efba8c4 100644 (file)
@@ -103,6 +103,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb,
                                    const struct net_device *in,
                                    const struct net_device *out,
                                    unsigned int hooknum,
+                                   const struct ipt_target *target,
                                    const void *targinfo,
                                    void *userinfo)
 {
@@ -145,6 +146,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb,
                                    const struct net_device *in,
                                    const struct net_device *out,
                                    unsigned int hooknum,
+                                   const struct ipt_target *target,
                                    const void *targinfo,
                                    void *userinfo)
 {
@@ -170,6 +172,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb,
 
 static int ipt_snat_checkentry(const char *tablename,
                               const void *entry,
+                              const struct ipt_target *target,
                               void *targinfo,
                               unsigned int targinfosize,
                               unsigned int hook_mask)
@@ -181,28 +184,12 @@ static int ipt_snat_checkentry(const char *tablename,
                printk("SNAT: multiple ranges no longer supported\n");
                return 0;
        }
-
-       if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))) {
-               DEBUGP("SNAT: Target size %u wrong for %u ranges\n",
-                      targinfosize, mr->rangesize);
-               return 0;
-       }
-
-       /* Only allow these for NAT. */
-       if (strcmp(tablename, "nat") != 0) {
-               DEBUGP("SNAT: wrong table %s\n", tablename);
-               return 0;
-       }
-
-       if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
-               DEBUGP("SNAT: hook mask 0x%x bad\n", hook_mask);
-               return 0;
-       }
        return 1;
 }
 
 static int ipt_dnat_checkentry(const char *tablename,
                               const void *entry,
+                              const struct ipt_target *target,
                               void *targinfo,
                               unsigned int targinfosize,
                               unsigned int hook_mask)
@@ -214,24 +201,6 @@ static int ipt_dnat_checkentry(const char *tablename,
                printk("DNAT: multiple ranges no longer supported\n");
                return 0;
        }
-
-       if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))) {
-               DEBUGP("DNAT: Target size %u wrong for %u ranges\n",
-                      targinfosize, mr->rangesize);
-               return 0;
-       }
-
-       /* Only allow these for NAT. */
-       if (strcmp(tablename, "nat") != 0) {
-               DEBUGP("DNAT: wrong table %s\n", tablename);
-               return 0;
-       }
-
-       if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) {
-               DEBUGP("DNAT: hook mask 0x%x bad\n", hook_mask);
-               return 0;
-       }
-       
        return 1;
 }
 
@@ -299,12 +268,18 @@ int ip_nat_rule_find(struct sk_buff **pskb,
 static struct ipt_target ipt_snat_reg = {
        .name           = "SNAT",
        .target         = ipt_snat_target,
+       .targetsize     = sizeof(struct ip_nat_multi_range_compat),
+       .table          = "nat",
+       .hooks          = 1 << NF_IP_POST_ROUTING,
        .checkentry     = ipt_snat_checkentry,
 };
 
 static struct ipt_target ipt_dnat_reg = {
        .name           = "DNAT",
        .target         = ipt_dnat_target,
+       .targetsize     = sizeof(struct ip_nat_multi_range_compat),
+       .table          = "nat",
+       .hooks          = 1 << NF_IP_PRE_ROUTING,
        .checkentry     = ipt_dnat_checkentry,
 };
 
index 4f95d47..f029da2 100644 (file)
@@ -250,6 +250,7 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx,
        if (!asn1_id_decode(ctx, cls, con, tag))
                return 0;
                
+       def = len = 0;
        if (!asn1_length_decode(ctx, &def, &len))
                return 0;
                
@@ -669,7 +670,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
        unsigned char *eoc, *end, *p;
        unsigned long *lp, *id;
        unsigned long ul;
-       long  l;
+       long l;
        
        *obj = NULL;
        id = NULL;
@@ -699,11 +700,13 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
                return 0;
        }
        
+       type = 0;
        if (!snmp_tag_cls2syntax(tag, cls, &type)) {
                kfree(id);
                return 0;
        }
        
+       l = 0;
        switch (type) {
                case SNMP_INTEGER:
                        len = sizeof(long);
index 08f80e2..1655866 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 #include <linux/security.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 #include <net/route.h>
 
@@ -61,7 +62,7 @@ static unsigned int queue_dropped = 0;
 static unsigned int queue_user_dropped = 0;
 static struct sock *ipqnl;
 static LIST_HEAD(queue_list);
-static DECLARE_MUTEX(ipqnl_sem);
+static DEFINE_MUTEX(ipqnl_mutex);
 
 static void
 ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
@@ -539,7 +540,7 @@ ipq_rcv_sk(struct sock *sk, int len)
        struct sk_buff *skb;
        unsigned int qlen;
 
-       down(&ipqnl_sem);
+       mutex_lock(&ipqnl_mutex);
                        
        for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
                skb = skb_dequeue(&sk->sk_receive_queue);
@@ -547,7 +548,7 @@ ipq_rcv_sk(struct sock *sk, int len)
                kfree_skb(skb);
        }
                
-       up(&ipqnl_sem);
+       mutex_unlock(&ipqnl_mutex);
 }
 
 static int
@@ -708,8 +709,8 @@ cleanup_sysctl:
        
 cleanup_ipqnl:
        sock_release(ipqnl->sk_socket);
-       down(&ipqnl_sem);
-       up(&ipqnl_sem);
+       mutex_lock(&ipqnl_mutex);
+       mutex_unlock(&ipqnl_mutex);
        
 cleanup_netlink_notifier:
        netlink_unregister_notifier(&ipq_nl_notifier);
index 16f47c6..39705f9 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/icmp.h>
 #include <net/ip.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/proc_fs.h>
 #include <linux/err.h>
 #include <linux/cpumask.h>
@@ -179,6 +179,7 @@ ipt_error(struct sk_buff **pskb,
          const struct net_device *in,
          const struct net_device *out,
          unsigned int hooknum,
+         const struct xt_target *target,
          const void *targinfo,
          void *userinfo)
 {
@@ -197,8 +198,8 @@ int do_match(struct ipt_entry_match *m,
             int *hotdrop)
 {
        /* Stop iteration if it doesn't match */
-       if (!m->u.kernel.match->match(skb, in, out, m->data, offset, 
-           skb->nh.iph->ihl*4, hotdrop))
+       if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
+                                     offset, skb->nh.iph->ihl*4, hotdrop))
                return 1;
        else
                return 0;
@@ -305,6 +306,7 @@ ipt_do_table(struct sk_buff **pskb,
                                verdict = t->u.kernel.target->target(pskb,
                                                                     in, out,
                                                                     hook,
+                                                                    t->u.kernel.target,
                                                                     t->data,
                                                                     userdata);
 
@@ -464,7 +466,7 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i)
                return 1;
 
        if (m->u.kernel.match->destroy)
-               m->u.kernel.match->destroy(m->data,
+               m->u.kernel.match->destroy(m->u.kernel.match, m->data,
                                           m->u.match_size - sizeof(*m));
        module_put(m->u.kernel.match->me);
        return 0;
@@ -477,21 +479,12 @@ standard_check(const struct ipt_entry_target *t,
        struct ipt_standard_target *targ = (void *)t;
 
        /* Check standard info. */
-       if (t->u.target_size
-           != IPT_ALIGN(sizeof(struct ipt_standard_target))) {
-               duprintf("standard_check: target size %u != %u\n",
-                        t->u.target_size,
-                        IPT_ALIGN(sizeof(struct ipt_standard_target)));
-               return 0;
-       }
-
        if (targ->verdict >= 0
            && targ->verdict > max_offset - sizeof(struct ipt_entry)) {
                duprintf("ipt_standard_check: bad verdict (%i)\n",
                         targ->verdict);
                return 0;
        }
-
        if (targ->verdict < -NF_MAX_VERDICT - 1) {
                duprintf("ipt_standard_check: bad negative verdict (%i)\n",
                         targ->verdict);
@@ -508,6 +501,7 @@ check_match(struct ipt_entry_match *m,
            unsigned int *i)
 {
        struct ipt_match *match;
+       int ret;
 
        match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
                                                   m->u.user.revision),
@@ -518,18 +512,27 @@ check_match(struct ipt_entry_match *m,
        }
        m->u.kernel.match = match;
 
+       ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m),
+                            name, hookmask, ip->proto,
+                            ip->invflags & IPT_INV_PROTO);
+       if (ret)
+               goto err;
+
        if (m->u.kernel.match->checkentry
-           && !m->u.kernel.match->checkentry(name, ip, m->data,
+           && !m->u.kernel.match->checkentry(name, ip, match, m->data,
                                              m->u.match_size - sizeof(*m),
                                              hookmask)) {
-               module_put(m->u.kernel.match->me);
                duprintf("ip_tables: check failed for `%s'.\n",
                         m->u.kernel.match->name);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
 
        (*i)++;
        return 0;
+err:
+       module_put(m->u.kernel.match->me);
+       return ret;
 }
 
 static struct ipt_target ipt_standard_target;
@@ -565,26 +568,32 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
        }
        t->u.kernel.target = target;
 
+       ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
+                             name, e->comefrom, e->ip.proto,
+                             e->ip.invflags & IPT_INV_PROTO);
+       if (ret)
+               goto err;
+
        if (t->u.kernel.target == &ipt_standard_target) {
                if (!standard_check(t, size)) {
                        ret = -EINVAL;
                        goto cleanup_matches;
                }
        } else if (t->u.kernel.target->checkentry
-                  && !t->u.kernel.target->checkentry(name, e, t->data,
+                  && !t->u.kernel.target->checkentry(name, e, target, t->data,
                                                      t->u.target_size
                                                      - sizeof(*t),
                                                      e->comefrom)) {
-               module_put(t->u.kernel.target->me);
                duprintf("ip_tables: check failed for `%s'.\n",
                         t->u.kernel.target->name);
                ret = -EINVAL;
-               goto cleanup_matches;
+               goto err;
        }
 
        (*i)++;
        return 0;
-
+ err:
+       module_put(t->u.kernel.target->me);
  cleanup_matches:
        IPT_MATCH_ITERATE(e, cleanup_match, &j);
        return ret;
@@ -645,7 +654,7 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i)
        IPT_MATCH_ITERATE(e, cleanup_match, NULL);
        t = ipt_get_target(e);
        if (t->u.kernel.target->destroy)
-               t->u.kernel.target->destroy(t->data,
+               t->u.kernel.target->destroy(t->u.kernel.target, t->data,
                                            t->u.target_size - sizeof(*t));
        module_put(t->u.kernel.target->me);
        return 0;
@@ -1277,6 +1286,7 @@ static int
 icmp_match(const struct sk_buff *skb,
           const struct net_device *in,
           const struct net_device *out,
+          const struct xt_match *match,
           const void *matchinfo,
           int offset,
           unsigned int protoff,
@@ -1310,28 +1320,27 @@ icmp_match(const struct sk_buff *skb,
 static int
 icmp_checkentry(const char *tablename,
           const void *info,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
-       const struct ipt_ip *ip = info;
        const struct ipt_icmp *icmpinfo = matchinfo;
 
-       /* Must specify proto == ICMP, and no unknown invflags */
-       return ip->proto == IPPROTO_ICMP
-               && !(ip->invflags & IPT_INV_PROTO)
-               && matchsize == IPT_ALIGN(sizeof(struct ipt_icmp))
-               && !(icmpinfo->invflags & ~IPT_ICMP_INV);
+       /* Must specify no unknown invflags */
+       return !(icmpinfo->invflags & ~IPT_ICMP_INV);
 }
 
 /* The built-in targets: standard (NULL) and error. */
 static struct ipt_target ipt_standard_target = {
        .name           = IPT_STANDARD_TARGET,
+       .targetsize     = sizeof(int),
 };
 
 static struct ipt_target ipt_error_target = {
        .name           = IPT_ERROR_TARGET,
        .target         = ipt_error,
+       .targetsize     = IPT_FUNCTION_MAXNAMELEN,
 };
 
 static struct nf_sockopt_ops ipt_sockopts = {
@@ -1346,8 +1355,10 @@ static struct nf_sockopt_ops ipt_sockopts = {
 
 static struct ipt_match icmp_matchstruct = {
        .name           = "icmp",
-       .match          = &icmp_match,
-       .checkentry     = &icmp_checkentry,
+       .match          = icmp_match,
+       .matchsize      = sizeof(struct ipt_icmp),
+       .proto          = IPPROTO_ICMP,
+       .checkentry     = icmp_checkentry,
 };
 
 static int __init init(void)
index d9bc971..61e11ed 100644 (file)
@@ -311,6 +311,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -380,6 +381,7 @@ target(struct sk_buff **pskb,
 static int
 checkentry(const char *tablename,
           const void *e_void,
+          const struct xt_target *target,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
@@ -389,13 +391,6 @@ checkentry(const char *tablename,
 
        struct clusterip_config *config;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info))) {
-               printk(KERN_WARNING "CLUSTERIP: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)));
-               return 0;
-       }
-
        if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
            cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
            cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
@@ -465,9 +460,10 @@ checkentry(const char *tablename,
 }
 
 /* drop reference count of cluster config when rule is deleted */
-static void destroy(void *matchinfo, unsigned int matchinfosize)
+static void destroy(const struct xt_target *target, void *targinfo,
+                   unsigned int targinfosize)
 {
-       struct ipt_clusterip_tgt_info *cipinfo = matchinfo;
+       struct ipt_clusterip_tgt_info *cipinfo = targinfo;
 
        /* if no more entries are referencing the config, remove it
         * from the list and destroy the proc entry */
@@ -476,12 +472,13 @@ static void destroy(void *matchinfo, unsigned int matchinfosize)
        clusterip_config_put(cipinfo->config);
 }
 
-static struct ipt_target clusterip_tgt = { 
-       .name = "CLUSTERIP",
-       .target = &target, 
-       .checkentry = &checkentry, 
-       .destroy = &destroy,
-       .me = THIS_MODULE
+static struct ipt_target clusterip_tgt = {
+       .name           = "CLUSTERIP",
+       .target         = target,
+       .targetsize     = sizeof(struct ipt_clusterip_tgt_info),
+       .checkentry     = checkentry,
+       .destroy        = destroy,
+       .me             = THIS_MODULE
 };
 
 
index 898cdf7..cfb0b90 100644 (file)
@@ -29,6 +29,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -58,35 +59,25 @@ target(struct sk_buff **pskb,
 static int
 checkentry(const char *tablename,
           const void *e_void,
+          const struct xt_target *target,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
        const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) {
-               printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_DSCP_info)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
        if ((dscp > IPT_DSCP_MAX)) {
                printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_target ipt_dscp_reg = {
        .name           = "DSCP",
        .target         = target,
+       .targetsize     = sizeof(struct ipt_DSCP_info),
+       .table          = "mangle",
        .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
index 7064454..b9b80f9 100644 (file)
@@ -94,6 +94,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -114,6 +115,7 @@ target(struct sk_buff **pskb,
 static int
 checkentry(const char *tablename,
           const void *e_void,
+          const struct xt_target *target,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
@@ -121,18 +123,6 @@ checkentry(const char *tablename,
        const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
        const struct ipt_entry *e = e_void;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
-               printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_ECN_info)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
        if (einfo->operation & IPT_ECN_OP_MASK) {
                printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
                        einfo->operation);
@@ -143,20 +133,20 @@ checkentry(const char *tablename,
                        einfo->ip_ect);
                return 0;
        }
-
        if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
            && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) {
                printk(KERN_WARNING "ECN: cannot use TCP operations on a "
                       "non-tcp rule\n");
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_target ipt_ecn_reg = {
        .name           = "ECN",
        .target         = target,
+       .targetsize     = sizeof(struct ipt_ECN_info),
+       .table          = "mangle",
        .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
index cc27545..750d322 100644 (file)
@@ -415,6 +415,7 @@ ipt_log_target(struct sk_buff **pskb,
               const struct net_device *in,
               const struct net_device *out,
               unsigned int hooknum,
+              const struct xt_target *target,
               const void *targinfo,
               void *userinfo)
 {
@@ -437,35 +438,29 @@ ipt_log_target(struct sk_buff **pskb,
 
 static int ipt_log_checkentry(const char *tablename,
                              const void *e,
+                             const struct xt_target *target,
                              void *targinfo,
                              unsigned int targinfosize,
                              unsigned int hook_mask)
 {
        const struct ipt_log_info *loginfo = targinfo;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_log_info))) {
-               DEBUGP("LOG: targinfosize %u != %u\n",
-                      targinfosize, IPT_ALIGN(sizeof(struct ipt_log_info)));
-               return 0;
-       }
-
        if (loginfo->level >= 8) {
                DEBUGP("LOG: level %u >= 8\n", loginfo->level);
                return 0;
        }
-
        if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
                DEBUGP("LOG: prefix term %i\n",
                       loginfo->prefix[sizeof(loginfo->prefix)-1]);
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_target ipt_log_reg = {
        .name           = "LOG",
        .target         = ipt_log_target,
+       .targetsize     = sizeof(struct ipt_log_info),
        .checkentry     = ipt_log_checkentry,
        .me             = THIS_MODULE,
 };
index 12c56d3..e0c321c 100644 (file)
@@ -41,25 +41,13 @@ static DEFINE_RWLOCK(masq_lock);
 static int
 masquerade_check(const char *tablename,
                 const void *e,
+                const struct xt_target *target,
                 void *targinfo,
                 unsigned int targinfosize,
                 unsigned int hook_mask)
 {
        const struct ip_nat_multi_range_compat *mr = targinfo;
 
-       if (strcmp(tablename, "nat") != 0) {
-               DEBUGP("masquerade_check: bad table `%s'.\n", tablename);
-               return 0;
-       }
-       if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
-               DEBUGP("masquerade_check: size %u != %u.\n",
-                      targinfosize, sizeof(*mr));
-               return 0;
-       }
-       if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
-               DEBUGP("masquerade_check: bad hooks %x.\n", hook_mask);
-               return 0;
-       }
        if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
                DEBUGP("masquerade_check: bad MAP_IPS.\n");
                return 0;
@@ -76,6 +64,7 @@ masquerade_target(struct sk_buff **pskb,
                  const struct net_device *in,
                  const struct net_device *out,
                  unsigned int hooknum,
+                 const struct xt_target *target,
                  const void *targinfo,
                  void *userinfo)
 {
@@ -179,6 +168,9 @@ static struct notifier_block masq_inet_notifier = {
 static struct ipt_target masquerade = {
        .name           = "MASQUERADE",
        .target         = masquerade_target,
+       .targetsize     = sizeof(struct ip_nat_multi_range_compat),
+       .table          = "nat",
+       .hooks          = 1 << NF_IP_POST_ROUTING,
        .checkentry     = masquerade_check,
        .me             = THIS_MODULE,
 };
index b074467..fba181c 100644 (file)
@@ -32,25 +32,13 @@ MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target");
 static int
 check(const char *tablename,
       const void *e,
+      const struct xt_target *target,
       void *targinfo,
       unsigned int targinfosize,
       unsigned int hook_mask)
 {
        const struct ip_nat_multi_range_compat *mr = targinfo;
 
-       if (strcmp(tablename, "nat") != 0) {
-               DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename);
-               return 0;
-       }
-       if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
-               DEBUGP(MODULENAME":check: size %u.\n", targinfosize);
-               return 0;
-       }
-       if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
-                         (1 << NF_IP_LOCAL_OUT))) {
-               DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask);
-               return 0;
-       }
        if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
                DEBUGP(MODULENAME":check: bad MAP_IPS.\n");
                return 0;
@@ -67,6 +55,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -101,6 +90,10 @@ target(struct sk_buff **pskb,
 static struct ipt_target target_module = { 
        .name           = MODULENAME,
        .target         = target, 
+       .targetsize     = sizeof(struct ip_nat_multi_range_compat),
+       .table          = "nat",
+       .hooks          = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
+                         (1 << NF_IP_LOCAL_OUT),
        .checkentry     = check,
        .me             = THIS_MODULE 
 };
index 140be51..be3da7c 100644 (file)
@@ -34,24 +34,13 @@ MODULE_DESCRIPTION("iptables REDIRECT target module");
 static int
 redirect_check(const char *tablename,
               const void *e,
+              const struct xt_target *target,
               void *targinfo,
               unsigned int targinfosize,
               unsigned int hook_mask)
 {
        const struct ip_nat_multi_range_compat *mr = targinfo;
 
-       if (strcmp(tablename, "nat") != 0) {
-               DEBUGP("redirect_check: bad table `%s'.\n", table);
-               return 0;
-       }
-       if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
-               DEBUGP("redirect_check: size %u.\n", targinfosize);
-               return 0;
-       }
-       if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) {
-               DEBUGP("redirect_check: bad hooks %x.\n", hook_mask);
-               return 0;
-       }
        if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
                DEBUGP("redirect_check: bad MAP_IPS.\n");
                return 0;
@@ -68,6 +57,7 @@ redirect_target(struct sk_buff **pskb,
                const struct net_device *in,
                const struct net_device *out,
                unsigned int hooknum,
+               const struct xt_target *target,
                const void *targinfo,
                void *userinfo)
 {
@@ -115,6 +105,9 @@ redirect_target(struct sk_buff **pskb,
 static struct ipt_target redirect_reg = {
        .name           = "REDIRECT",
        .target         = redirect_target,
+       .targetsize     = sizeof(struct ip_nat_multi_range_compat),
+       .table          = "nat",
+       .hooks          = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
        .checkentry     = redirect_check,
        .me             = THIS_MODULE,
 };
index 3eb47aa..9d3b357 100644 (file)
@@ -154,10 +154,6 @@ static void send_reset(struct sk_buff *oldskb, int hook)
        /* This packet will not be the same as the other: clear nf fields */
        nf_reset(nskb);
        nskb->nfmark = 0;
-#ifdef CONFIG_BRIDGE_NETFILTER
-       nf_bridge_put(nskb->nf_bridge);
-       nskb->nf_bridge = NULL;
-#endif
 
        tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
 
@@ -236,6 +232,7 @@ static unsigned int reject(struct sk_buff **pskb,
                           const struct net_device *in,
                           const struct net_device *out,
                           unsigned int hooknum,
+                          const struct xt_target *target,
                           const void *targinfo,
                           void *userinfo)
 {
@@ -283,6 +280,7 @@ static unsigned int reject(struct sk_buff **pskb,
 
 static int check(const char *tablename,
                 const void *e_void,
+                const struct xt_target *target,
                 void *targinfo,
                 unsigned int targinfosize,
                 unsigned int hook_mask)
@@ -290,23 +288,6 @@ static int check(const char *tablename,
        const struct ipt_reject_info *rejinfo = targinfo;
        const struct ipt_entry *e = e_void;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
-               DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
-               return 0;
-       }
-
-       /* Only allow these for packet filtering. */
-       if (strcmp(tablename, "filter") != 0) {
-               DEBUGP("REJECT: bad table `%s'.\n", tablename);
-               return 0;
-       }
-       if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
-                          | (1 << NF_IP_FORWARD)
-                          | (1 << NF_IP_LOCAL_OUT))) != 0) {
-               DEBUGP("REJECT: bad hook mask %X\n", hook_mask);
-               return 0;
-       }
-
        if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
                printk("REJECT: ECHOREPLY no longer supported.\n");
                return 0;
@@ -318,13 +299,16 @@ static int check(const char *tablename,
                        return 0;
                }
        }
-
        return 1;
 }
 
 static struct ipt_target ipt_reject_reg = {
        .name           = "REJECT",
        .target         = reject,
+       .targetsize     = sizeof(struct ipt_reject_info),
+       .table          = "filter",
+       .hooks          = (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) |
+                         (1 << NF_IP_LOCAL_OUT),
        .checkentry     = check,
        .me             = THIS_MODULE,
 };
index a22de59..7e2ebc9 100644 (file)
@@ -50,6 +50,7 @@ MODULE_DESCRIPTION("iptables special SNAT module for consistent sourceip");
 static int
 same_check(const char *tablename,
              const void *e,
+             const struct xt_target *target,
              void *targinfo,
              unsigned int targinfosize,
              unsigned int hook_mask)
@@ -59,18 +60,6 @@ same_check(const char *tablename,
 
        mr->ipnum = 0;
 
-       if (strcmp(tablename, "nat") != 0) {
-               DEBUGP("same_check: bad table `%s'.\n", tablename);
-               return 0;
-       }
-       if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
-               DEBUGP("same_check: size %u.\n", targinfosize);
-               return 0;
-       }
-       if (hook_mask & ~(1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING)) {
-               DEBUGP("same_check: bad hooks %x.\n", hook_mask);
-               return 0;
-       }
        if (mr->rangesize < 1) {
                DEBUGP("same_check: need at least one dest range.\n");
                return 0;
@@ -127,7 +116,7 @@ same_check(const char *tablename,
 }
 
 static void 
-same_destroy(void *targinfo,
+same_destroy(const struct xt_target *target, void *targinfo,
                unsigned int targinfosize)
 {
        struct ipt_same_info *mr = targinfo;
@@ -143,6 +132,7 @@ same_target(struct sk_buff **pskb,
                const struct net_device *in,
                const struct net_device *out,
                unsigned int hooknum,
+               const struct xt_target *target,
                const void *targinfo,
                void *userinfo)
 {
@@ -191,6 +181,9 @@ same_target(struct sk_buff **pskb,
 static struct ipt_target same_reg = { 
        .name           = "SAME",
        .target         = same_target,
+       .targetsize     = sizeof(struct ipt_same_info),
+       .table          = "nat",
+       .hooks          = (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING),
        .checkentry     = same_check,
        .destroy        = same_destroy,
        .me             = THIS_MODULE,
index c122841..c4fc50e 100644 (file)
@@ -48,6 +48,7 @@ ipt_tcpmss_target(struct sk_buff **pskb,
                  const struct net_device *in,
                  const struct net_device *out,
                  unsigned int hooknum,
+                 const struct xt_target *target,
                  const void *targinfo,
                  void *userinfo)
 {
@@ -211,6 +212,7 @@ static inline int find_syn_match(const struct ipt_entry_match *m)
 static int
 ipt_tcpmss_checkentry(const char *tablename,
                      const void *e_void,
+                     const struct xt_target *target,
                      void *targinfo,
                      unsigned int targinfosize,
                      unsigned int hook_mask)
@@ -218,13 +220,6 @@ ipt_tcpmss_checkentry(const char *tablename,
        const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
        const struct ipt_entry *e = e_void;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) {
-               DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n",
-                      targinfosize, IPT_ALIGN(sizeof(struct ipt_tcpmss_info)));
-               return 0;
-       }
-
-
        if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && 
                        ((hook_mask & ~((1 << NF_IP_FORWARD)
                                | (1 << NF_IP_LOCAL_OUT)
@@ -233,11 +228,8 @@ ipt_tcpmss_checkentry(const char *tablename,
                return 0;
        }
 
-       if (e->ip.proto == IPPROTO_TCP
-           && !(e->ip.invflags & IPT_INV_PROTO)
-           && IPT_MATCH_ITERATE(e, find_syn_match))
+       if (IPT_MATCH_ITERATE(e, find_syn_match))
                return 1;
-
        printk("TCPMSS: Only works on TCP SYN packets\n");
        return 0;
 }
@@ -245,6 +237,8 @@ ipt_tcpmss_checkentry(const char *tablename,
 static struct ipt_target ipt_tcpmss_reg = {
        .name           = "TCPMSS",
        .target         = ipt_tcpmss_target,
+       .targetsize     = sizeof(struct ipt_tcpmss_info),
+       .proto          = IPPROTO_TCP,
        .checkentry     = ipt_tcpmss_checkentry,
        .me             = THIS_MODULE,
 };
index 3a44a56..9aa7817 100644 (file)
@@ -25,6 +25,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -53,24 +54,13 @@ target(struct sk_buff **pskb,
 static int
 checkentry(const char *tablename,
           const void *e_void,
+          const struct xt_target *target,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
        const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tos_target_info))) {
-               printk(KERN_WARNING "TOS: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_tos_target_info)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_WARNING "TOS: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
        if (tos != IPTOS_LOWDELAY
            && tos != IPTOS_THROUGHPUT
            && tos != IPTOS_RELIABILITY
@@ -79,13 +69,14 @@ checkentry(const char *tablename,
                printk(KERN_WARNING "TOS: bad tos value %#x\n", tos);
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_target ipt_tos_reg = {
        .name           = "TOS",
        .target         = target,
+       .targetsize     = sizeof(struct ipt_tos_target_info),
+       .table          = "mangle",
        .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
index b769eb2..5009a00 100644 (file)
@@ -20,9 +20,10 @@ MODULE_DESCRIPTION("IP tables TTL modification module");
 MODULE_LICENSE("GPL");
 
 static unsigned int 
-ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, 
-               const struct net_device *out, unsigned int hooknum, 
-               const void *targinfo, void *userinfo)
+ipt_ttl_target(struct sk_buff **pskb,
+              const struct net_device *in, const struct net_device *out,
+              unsigned int hooknum, const struct xt_target *target,
+              const void *targinfo, void *userinfo)
 {
        struct iphdr *iph;
        const struct ipt_TTL_info *info = targinfo;
@@ -67,40 +68,28 @@ ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
 
 static int ipt_ttl_checkentry(const char *tablename,
                const void *e,
+               const struct xt_target *target,
                void *targinfo,
                unsigned int targinfosize,
                unsigned int hook_mask)
 {
        struct ipt_TTL_info *info = targinfo;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
-               printk(KERN_WARNING "ipt_TTL: targinfosize %u != %Zu\n",
-                               targinfosize,
-                               IPT_ALIGN(sizeof(struct ipt_TTL_info)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle")) {
-               printk(KERN_WARNING "ipt_TTL: can only be called from "
-                       "\"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
        if (info->mode > IPT_TTL_MAXMODE) {
                printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", 
                        info->mode);
                return 0;
        }
-
        if ((info->mode != IPT_TTL_SET) && (info->ttl == 0))
                return 0;
-
        return 1;
 }
 
 static struct ipt_target ipt_TTL = { 
        .name           = "TTL",
        .target         = ipt_ttl_target, 
+       .targetsize     = sizeof(struct ipt_TTL_info),
+       .table          = "mangle",
        .checkentry     = ipt_ttl_checkentry, 
        .me             = THIS_MODULE,
 };
index 180a9ea..a82a32e 100644 (file)
@@ -303,6 +303,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
                                    const struct net_device *in,
                                    const struct net_device *out,
                                    unsigned int hooknum,
+                                   const struct xt_target *target,
                                    const void *targinfo, void *userinfo)
 {
        struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
@@ -339,42 +340,37 @@ static void ipt_logfn(unsigned int pf,
 
 static int ipt_ulog_checkentry(const char *tablename,
                               const void *e,
+                              const struct xt_target *target,
                               void *targinfo,
                               unsigned int targinfosize,
                               unsigned int hookmask)
 {
        struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
-               DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
-               return 0;
-       }
-
        if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
                DEBUGP("ipt_ULOG: prefix term %i\n",
                       loginfo->prefix[sizeof(loginfo->prefix) - 1]);
                return 0;
        }
-
        if (loginfo->qthreshold > ULOG_MAX_QLEN) {
                DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
                        loginfo->qthreshold);
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_target ipt_ulog_reg = {
        .name           = "ULOG",
        .target         = ipt_ulog_target,
+       .targetsize     = sizeof(struct ipt_ulog_info),
        .checkentry     = ipt_ulog_checkentry,
        .me             = THIS_MODULE,
 };
 
 static struct nf_logger ipt_ulog_logger = {
        .name           = "ipt_ULOG",
-       .logfn          = &ipt_logfn,
+       .logfn          = ipt_logfn,
        .me             = THIS_MODULE,
 };
 
index d6b83a9..5fdf85d 100644 (file)
@@ -27,8 +27,9 @@ static inline int match_type(u_int32_t addr, u_int16_t mask)
        return !!(mask & (1 << inet_addr_type(addr)));
 }
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-                const struct net_device *out, const void *matchinfo,
+static int match(const struct sk_buff *skb,
+                const struct net_device *in, const struct net_device *out,
+                const struct xt_match *match, const void *matchinfo,
                 int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_addrtype_info *info = matchinfo;
@@ -43,23 +44,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return ret;
 }
 
-static int checkentry(const char *tablename, const void *ip,
-                     void *matchinfo, unsigned int matchsize,
-                     unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_addrtype_info))) {
-               printk(KERN_ERR "ipt_addrtype: invalid size (%u != %Zu)\n",
-                      matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info)));
-               return 0;
-       }
-
-       return 1;
-}
-
 static struct ipt_match addrtype_match = {
        .name           = "addrtype",
        .match          = match,
-       .checkentry     = checkentry,
+       .matchsize      = sizeof(struct ipt_addrtype_info),
        .me             = THIS_MODULE
 };
 
index 144adfe..35a21fb 100644 (file)
@@ -39,6 +39,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -71,37 +72,27 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *ip_void,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ipt_ah *ahinfo = matchinfo;
-       const struct ipt_ip *ip = ip_void;
 
-       /* Must specify proto == AH, and no unknown invflags */
-       if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
-               duprintf("ipt_ah: Protocol %u != %u\n", ip->proto,
-                        IPPROTO_AH);
-               return 0;
-       }
-       if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) {
-               duprintf("ipt_ah: matchsize %u != %u\n",
-                        matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah)));
-               return 0;
-       }
+       /* Must specify no unknown invflags */
        if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
-               duprintf("ipt_ah: unknown flags %X\n",
-                        ahinfo->invflags);
+               duprintf("ipt_ah: unknown flags %X\n", ahinfo->invflags);
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_match ah_match = {
        .name           = "ah",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_ah),
+       .proto          = IPPROTO_AH,
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 92063b4..11963c3 100644 (file)
@@ -19,8 +19,9 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("iptables DSCP matching module");
 MODULE_LICENSE("GPL");
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-                const struct net_device *out, const void *matchinfo,
+static int match(const struct sk_buff *skb,
+                const struct net_device *in, const struct net_device *out,
+                const struct xt_match *match, const void *matchinfo,
                 int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_dscp_info *info = matchinfo;
@@ -31,20 +32,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
 }
 
-static int checkentry(const char *tablename, const void *ip,
-                     void *matchinfo, unsigned int matchsize,
-                     unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_dscp_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct ipt_match dscp_match = {
        .name           = "dscp",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_dscp_info),
        .me             = THIS_MODULE,
 };
 
index e68b0c7..d7e29f6 100644 (file)
@@ -65,8 +65,9 @@ static inline int match_tcp(const struct sk_buff *skb,
        return 1;
 }
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-                const struct net_device *out, const void *matchinfo,
+static int match(const struct sk_buff *skb,
+                const struct net_device *in, const struct net_device *out,
+                const struct xt_match *match, const void *matchinfo,
                 int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_ecn_info *info = matchinfo;
@@ -86,15 +87,13 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
 }
 
 static int checkentry(const char *tablename, const void *ip_void,
+                     const struct xt_match *match,
                      void *matchinfo, unsigned int matchsize,
                      unsigned int hook_mask)
 {
        const struct ipt_ecn_info *info = matchinfo;
        const struct ipt_ip *ip = ip_void;
 
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
-               return 0;
-
        if (info->operation & IPT_ECN_OP_MATCH_MASK)
                return 0;
 
@@ -113,8 +112,9 @@ static int checkentry(const char *tablename, const void *ip_void,
 
 static struct ipt_match ecn_match = {
        .name           = "ecn",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_ecn_info),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 9de191a..af0d5ec 100644 (file)
@@ -40,6 +40,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -72,37 +73,27 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *ip_void,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ipt_esp *espinfo = matchinfo;
-       const struct ipt_ip *ip = ip_void;
 
-       /* Must specify proto == ESP, and no unknown invflags */
-       if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
-               duprintf("ipt_esp: Protocol %u != %u\n", ip->proto,
-                        IPPROTO_ESP);
-               return 0;
-       }
-       if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) {
-               duprintf("ipt_esp: matchsize %u != %u\n",
-                        matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp)));
-               return 0;
-       }
+       /* Must specify no unknown invflags */
        if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
-               duprintf("ipt_esp: unknown flags %X\n",
-                        espinfo->invflags);
+               duprintf("ipt_esp: unknown flags %X\n", espinfo->invflags);
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_match esp_match = {
        .name           = "esp",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_esp),
+       .proto          = IPPROTO_ESP,
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 4fe48c1..dc1521c 100644 (file)
@@ -427,6 +427,7 @@ static int
 hashlimit_match(const struct sk_buff *skb,
                const struct net_device *in,
                const struct net_device *out,
+               const struct xt_match *match,
                const void *matchinfo,
                int offset,
                unsigned int protoff,
@@ -506,15 +507,13 @@ hashlimit_match(const struct sk_buff *skb,
 static int
 hashlimit_checkentry(const char *tablename,
                     const void *inf,
+                    const struct xt_match *match,
                     void *matchinfo,
                     unsigned int matchsize,
                     unsigned int hook_mask)
 {
        struct ipt_hashlimit_info *r = matchinfo;
 
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_hashlimit_info)))
-               return 0;
-
        /* Check for overflow. */
        if (r->cfg.burst == 0
            || user2credits(r->cfg.avg * r->cfg.burst) < 
@@ -558,19 +557,21 @@ hashlimit_checkentry(const char *tablename,
 }
 
 static void
-hashlimit_destroy(void *matchinfo, unsigned int matchsize)
+hashlimit_destroy(const struct xt_match *match, void *matchinfo,
+                 unsigned int matchsize)
 {
        struct ipt_hashlimit_info *r = (struct ipt_hashlimit_info *) matchinfo;
 
        htable_put(r->hinfo);
 }
 
-static struct ipt_match ipt_hashlimit = { 
-       .name = "hashlimit", 
-       .match = hashlimit_match, 
-       .checkentry = hashlimit_checkentry, 
-       .destroy = hashlimit_destroy,
-       .me = THIS_MODULE 
+static struct ipt_match ipt_hashlimit = {
+       .name           = "hashlimit",
+       .match          = hashlimit_match,
+       .matchsize      = sizeof(struct ipt_hashlimit_info),
+       .checkentry     = hashlimit_checkentry,
+       .destroy        = hashlimit_destroy,
+       .me             = THIS_MODULE
 };
 
 /* PROC stuff */
index 13fb16f..ae70112 100644 (file)
@@ -27,6 +27,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset, unsigned int protoff, int *hotdrop)
 {
@@ -62,27 +63,12 @@ match(const struct sk_buff *skb,
        return 1;
 }
 
-static int check(const char *tablename,
-                const void *inf,
-                void *matchinfo,
-                unsigned int matchsize,
-                unsigned int hook_mask)
-{
-       /* verify size */
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_iprange_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ipt_match iprange_match = 
-{ 
-       .list = { NULL, NULL }, 
-       .name = "iprange", 
-       .match = &match, 
-       .checkentry = &check, 
-       .destroy = NULL, 
-       .me = THIS_MODULE
+static struct ipt_match iprange_match = {
+       .name           = "iprange",
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_iprange_info),
+       .destroy        = NULL,
+       .me             = THIS_MODULE
 };
 
 static int __init init(void)
index 2d52326..bd07f7c 100644 (file)
@@ -95,6 +95,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -127,6 +128,7 @@ static int
 match_v1(const struct sk_buff *skb,
         const struct net_device *in,
         const struct net_device *out,
+        const struct xt_match *match,
         const void *matchinfo,
         int offset,
         unsigned int protoff,
@@ -153,40 +155,19 @@ match_v1(const struct sk_buff *skb,
        return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
 }
 
-/* Called when user tries to insert an entry of this type. */
-static int
-checkentry(const char *tablename,
-          const void *ip,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-{
-       return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport)));
-}
-
-static int
-checkentry_v1(const char *tablename,
-             const void *ip,
-             void *matchinfo,
-             unsigned int matchsize,
-             unsigned int hook_mask)
-{
-       return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport_v1)));
-}
-
 static struct ipt_match multiport_match = {
        .name           = "multiport",
        .revision       = 0,
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_multiport),
        .me             = THIS_MODULE,
 };
 
 static struct ipt_match multiport_match_v1 = {
        .name           = "multiport",
        .revision       = 1,
-       .match          = &match_v1,
-       .checkentry     = &checkentry_v1,
+       .match          = match_v1,
+       .matchsize      = sizeof(struct ipt_multiport_v1),
        .me             = THIS_MODULE,
 };
 
index 4843d0c..3900428 100644 (file)
@@ -25,6 +25,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -53,37 +54,27 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
            const void *ip,
+          const struct xt_match *match,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
 {
        const struct ipt_owner_info *info = matchinfo;
 
-        if (hook_mask
-            & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) {
-                printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
-                return 0;
-        }
-
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) {
-               printk("Matchsize %u != %Zu\n", matchsize,
-                      IPT_ALIGN(sizeof(struct ipt_owner_info)));
-               return 0;
-       }
-
        if (info->match & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) {
                printk("ipt_owner: pid, sid and command matching "
                       "not supported anymore\n");
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_match owner_match = {
        .name           = "owner",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_owner_info),
+       .hooks          = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
diff --git a/net/ipv4/netfilter/ipt_policy.c b/net/ipv4/netfilter/ipt_policy.c
deleted file mode 100644 (file)
index 5a7a265..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/* IP tables module for matching IPsec policy
- *
- * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <net/xfrm.h>
-
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_policy.h>
-
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_DESCRIPTION("IPtables IPsec policy matching module");
-MODULE_LICENSE("GPL");
-
-
-static inline int
-match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
-{
-#define MATCH_ADDR(x,y,z)      (!e->match.x ||                              \
-                                ((e->x.a4.s_addr == (e->y.a4.s_addr & (z))) \
-                                 ^ e->invert.x))
-#define MATCH(x,y)             (!e->match.x || ((e->x == (y)) ^ e->invert.x))
-
-       return MATCH_ADDR(saddr, smask, x->props.saddr.a4) &&
-              MATCH_ADDR(daddr, dmask, x->id.daddr.a4) &&
-              MATCH(proto, x->id.proto) &&
-              MATCH(mode, x->props.mode) &&
-              MATCH(spi, x->id.spi) &&
-              MATCH(reqid, x->props.reqid);
-}
-
-static int
-match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info)
-{
-       const struct ipt_policy_elem *e;
-       struct sec_path *sp = skb->sp;
-       int strict = info->flags & IPT_POLICY_MATCH_STRICT;
-       int i, pos;
-
-       if (sp == NULL)
-               return -1;
-       if (strict && info->len != sp->len)
-               return 0;
-
-       for (i = sp->len - 1; i >= 0; i--) {
-               pos = strict ? i - sp->len + 1 : 0;
-               if (pos >= info->len)
-                       return 0;
-               e = &info->pol[pos];
-
-               if (match_xfrm_state(sp->x[i].xvec, e)) {
-                       if (!strict)
-                               return 1;
-               } else if (strict)
-                       return 0;
-       }
-
-       return strict ? 1 : 0;
-}
-
-static int
-match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
-{
-       const struct ipt_policy_elem *e;
-       struct dst_entry *dst = skb->dst;
-       int strict = info->flags & IPT_POLICY_MATCH_STRICT;
-       int i, pos;
-
-       if (dst->xfrm == NULL)
-               return -1;
-
-       for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
-               pos = strict ? i : 0;
-               if (pos >= info->len)
-                       return 0;
-               e = &info->pol[pos];
-
-               if (match_xfrm_state(dst->xfrm, e)) {
-                       if (!strict)
-                               return 1;
-               } else if (strict)
-                       return 0;
-       }
-
-       return strict ? i == info->len : 0;
-}
-
-static int match(const struct sk_buff *skb,
-                 const struct net_device *in,
-                 const struct net_device *out,
-                 const void *matchinfo,
-                 int offset,
-                 unsigned int protoff,
-                 int *hotdrop)
-{
-       const struct ipt_policy_info *info = matchinfo;
-       int ret;
-
-       if (info->flags & IPT_POLICY_MATCH_IN)
-               ret = match_policy_in(skb, info);
-       else
-               ret = match_policy_out(skb, info);
-
-       if (ret < 0)
-               ret = info->flags & IPT_POLICY_MATCH_NONE ? 1 : 0;
-       else if (info->flags & IPT_POLICY_MATCH_NONE)
-               ret = 0;
-
-       return ret;
-}
-
-static int checkentry(const char *tablename, const void *ip_void,
-                      void *matchinfo, unsigned int matchsize,
-                      unsigned int hook_mask)
-{
-       struct ipt_policy_info *info = matchinfo;
-
-       if (matchsize != IPT_ALIGN(sizeof(*info))) {
-               printk(KERN_ERR "ipt_policy: matchsize %u != %zu\n",
-                      matchsize, IPT_ALIGN(sizeof(*info)));
-               return 0;
-       }
-       if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) {
-               printk(KERN_ERR "ipt_policy: neither incoming nor "
-                               "outgoing policy selected\n");
-               return 0;
-       }
-       if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
-           && info->flags & IPT_POLICY_MATCH_OUT) {
-               printk(KERN_ERR "ipt_policy: output policy not valid in "
-                               "PRE_ROUTING and INPUT\n");
-               return 0;
-       }
-       if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
-           && info->flags & IPT_POLICY_MATCH_IN) {
-               printk(KERN_ERR "ipt_policy: input policy not valid in "
-                               "POST_ROUTING and OUTPUT\n");
-               return 0;
-       }
-       if (info->len > IPT_POLICY_MAX_ELEM) {
-               printk(KERN_ERR "ipt_policy: too many policy elements\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_match policy_match = {
-       .name           = "policy",
-       .match          = match,
-       .checkentry     = checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&policy_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&policy_match);
-}
-
-module_init(init);
-module_exit(fini);
index 44611d6..06792ea 100644 (file)
@@ -102,6 +102,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -318,7 +319,7 @@ static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned
        skb->nh.iph->daddr = 0;
        /* Clear ttl since we have no way of knowing it */
        skb->nh.iph->ttl = 0;
-       match(skb,NULL,NULL,info,0,0,NULL);
+       match(skb,NULL,NULL,NULL,info,0,0,NULL);
 
        kfree(skb->nh.iph);
 out_free_skb:
@@ -356,6 +357,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -657,6 +659,7 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
            const void *ip,
+          const struct xt_match *match,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
@@ -670,8 +673,6 @@ checkentry(const char *tablename,
        if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n");
 #endif
 
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return 0;
-
        /* seconds and hit_count only valid for CHECK/UPDATE */
        if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; }
        if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; }
@@ -871,7 +872,7 @@ checkentry(const char *tablename,
  * up its memory.
  */
 static void
-destroy(void *matchinfo, unsigned int matchsize)
+destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize)
 {
        const struct ipt_recent_info *info = matchinfo;
        struct recent_ip_tables *curr_table, *last_table;
@@ -951,12 +952,13 @@ destroy(void *matchinfo, unsigned int matchsize)
 /* This is the structure we pass to ipt_register to register our
  * module with iptables.
  */
-static struct ipt_match recent_match = { 
-  .name = "recent", 
-  .match = &match, 
-  .checkentry = &checkentry, 
-  .destroy = &destroy, 
-  .me = THIS_MODULE
+static struct ipt_match recent_match = {
+       .name           = "recent",
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_recent_info),
+       .checkentry     = checkentry,
+       .destroy        = destroy,
+       .me             = THIS_MODULE
 };
 
 /* Kernel module initialization. */
index 9ab765e..e404e92 100644 (file)
@@ -21,6 +21,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -31,23 +32,10 @@ match(const struct sk_buff *skb,
        return (skb->nh.iph->tos == info->tos) ^ info->invert;
 }
 
-static int
-checkentry(const char *tablename,
-           const void *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_tos_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct ipt_match tos_match = {
        .name           = "tos",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_tos_info),
        .me             = THIS_MODULE,
 };
 
index 82da53f..ae7ce4d 100644 (file)
@@ -19,8 +19,9 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("IP tables TTL matching module");
 MODULE_LICENSE("GPL");
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-                const struct net_device *out, const void *matchinfo,
+static int match(const struct sk_buff *skb,
+                const struct net_device *in, const struct net_device *out,
+                const struct xt_match *match, const void *matchinfo,
                 int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_ttl_info *info = matchinfo;
@@ -47,20 +48,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return 0;
 }
 
-static int checkentry(const char *tablename, const void  *ip,
-                     void *matchinfo, unsigned int matchsize,
-                     unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_ttl_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct ipt_match ttl_match = {
        .name           = "ttl",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ipt_ttl_info),
        .me             = THIS_MODULE,
 };
 
index 6c8624a..cb9c661 100644 (file)
@@ -141,19 +141,21 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
+       struct nf_conn_help *help;
 
        /* This is where we call the helper: as the packet goes out. */
        ct = nf_ct_get(*pskb, &ctinfo);
-       if (ct && ct->helper) {
-               unsigned int ret;
-               ret = ct->helper->help(pskb,
-                                      (*pskb)->nh.raw - (*pskb)->data
-                                                      + (*pskb)->nh.iph->ihl*4,
-                                      ct, ctinfo);
-               if (ret != NF_ACCEPT)
-                       return ret;
-       }
-       return NF_ACCEPT;
+       if (!ct)
+               return NF_ACCEPT;
+
+       help = nfct_help(ct);
+       if (!help || !help->helper)
+               return NF_ACCEPT;
+
+       return help->helper->help(pskb,
+                              (*pskb)->nh.raw - (*pskb)->data
+                                              + (*pskb)->nh.iph->ihl*4,
+                              ct, ctinfo);
 }
 
 static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
index f29a12d..fc25624 100644 (file)
@@ -660,12 +660,9 @@ static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *o
 out:   return ret;
 }
 
-static int raw_setsockopt(struct sock *sk, int level, int optname, 
+static int do_raw_setsockopt(struct sock *sk, int level, int optname,
                          char __user *optval, int optlen)
 {
-       if (level != SOL_RAW)
-               return ip_setsockopt(sk, level, optname, optval, optlen);
-
        if (optname == ICMP_FILTER) {
                if (inet_sk(sk)->num != IPPROTO_ICMP)
                        return -EOPNOTSUPP;
@@ -675,12 +672,27 @@ static int raw_setsockopt(struct sock *sk, int level, int optname,
        return -ENOPROTOOPT;
 }
 
-static int raw_getsockopt(struct sock *sk, int level, int optname, 
-                         char __user *optval, int __user *optlen)
+static int raw_setsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int optlen)
 {
        if (level != SOL_RAW)
-               return ip_getsockopt(sk, level, optname, optval, optlen);
+               return ip_setsockopt(sk, level, optname, optval, optlen);
+       return do_raw_setsockopt(sk, level, optname, optval, optlen);
+}
 
+#ifdef CONFIG_COMPAT
+static int compat_raw_setsockopt(struct sock *sk, int level, int optname,
+                                char __user *optval, int optlen)
+{
+       if (level != SOL_RAW)
+               return compat_ip_setsockopt(sk, level, optname, optval, optlen);
+       return do_raw_setsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
+static int do_raw_getsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
        if (optname == ICMP_FILTER) {
                if (inet_sk(sk)->num != IPPROTO_ICMP)
                        return -EOPNOTSUPP;
@@ -690,6 +702,24 @@ static int raw_getsockopt(struct sock *sk, int level, int optname,
        return -ENOPROTOOPT;
 }
 
+static int raw_getsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       if (level != SOL_RAW)
+               return ip_getsockopt(sk, level, optname, optval, optlen);
+       return do_raw_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_raw_getsockopt(struct sock *sk, int level, int optname,
+                                char __user *optval, int __user *optlen)
+{
+       if (level != SOL_RAW)
+               return compat_ip_getsockopt(sk, level, optname, optval, optlen);
+       return do_raw_getsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
 static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        switch (cmd) {
@@ -719,22 +749,26 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
 }
 
 struct proto raw_prot = {
-       .name =         "RAW",
-       .owner =        THIS_MODULE,
-       .close =        raw_close,
-       .connect =      ip4_datagram_connect,
-       .disconnect =   udp_disconnect,
-       .ioctl =        raw_ioctl,
-       .init =         raw_init,
-       .setsockopt =   raw_setsockopt,
-       .getsockopt =   raw_getsockopt,
-       .sendmsg =      raw_sendmsg,
-       .recvmsg =      raw_recvmsg,
-       .bind =         raw_bind,
-       .backlog_rcv =  raw_rcv_skb,
-       .hash =         raw_v4_hash,
-       .unhash =       raw_v4_unhash,
-       .obj_size =     sizeof(struct raw_sock),
+       .name              = "RAW",
+       .owner             = THIS_MODULE,
+       .close             = raw_close,
+       .connect           = ip4_datagram_connect,
+       .disconnect        = udp_disconnect,
+       .ioctl             = raw_ioctl,
+       .init              = raw_init,
+       .setsockopt        = raw_setsockopt,
+       .getsockopt        = raw_getsockopt,
+       .sendmsg           = raw_sendmsg,
+       .recvmsg           = raw_recvmsg,
+       .bind              = raw_bind,
+       .backlog_rcv       = raw_rcv_skb,
+       .hash              = raw_v4_hash,
+       .unhash            = raw_v4_unhash,
+       .obj_size          = sizeof(struct raw_sock),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_raw_setsockopt,
+       .compat_getsockopt = compat_raw_getsockopt,
+#endif
 };
 
 #ifdef CONFIG_PROC_FS
index 16984d4..6b6c3ad 100644 (file)
@@ -664,7 +664,30 @@ ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
-
+       {
+               .ctl_name       = NET_TCP_MTU_PROBING,
+               .procname       = "tcp_mtu_probing",
+               .data           = &sysctl_tcp_mtu_probing,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       {
+               .ctl_name       = NET_TCP_BASE_MSS,
+               .procname       = "tcp_base_mss",
+               .data           = &sysctl_tcp_base_mss,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+        {
+               .ctl_name       = NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS,
+               .procname       = "tcp_workaround_signed_windows",
+               .data           = &sysctl_tcp_workaround_signed_windows,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
        { .ctl_name = 0 }
 };
 
index 00aa80e..4b0272c 100644 (file)
@@ -1687,18 +1687,14 @@ int tcp_disconnect(struct sock *sk, int flags)
 /*
  *     Socket option code for TCP.
  */
-int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
-                  int optlen)
+static int do_tcp_setsockopt(struct sock *sk, int level,
+               int optname, char __user *optval, int optlen)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
        int val;
        int err = 0;
 
-       if (level != SOL_TCP)
-               return icsk->icsk_af_ops->setsockopt(sk, level, optname,
-                                                    optval, optlen);
-
        /* This is a string value all the others are int's */
        if (optname == TCP_CONGESTION) {
                char name[TCP_CA_NAME_MAX];
@@ -1871,6 +1867,30 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
        return err;
 }
 
+int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
+                  int optlen)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (level != SOL_TCP)
+               return icsk->icsk_af_ops->setsockopt(sk, level, optname,
+                                                    optval, optlen);
+       return do_tcp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int optlen)
+{
+       if (level != SOL_TCP)
+               return inet_csk_compat_setsockopt(sk, level, optname,
+                                                 optval, optlen);
+       return do_tcp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL(compat_tcp_setsockopt);
+#endif
+
 /* Return information about state of tcp endpoint in API format. */
 void tcp_get_info(struct sock *sk, struct tcp_info *info)
 {
@@ -1931,17 +1951,13 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
 
 EXPORT_SYMBOL_GPL(tcp_get_info);
 
-int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
-                  int __user *optlen)
+static int do_tcp_getsockopt(struct sock *sk, int level,
+               int optname, char __user *optval, int __user *optlen)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        int val, len;
 
-       if (level != SOL_TCP)
-               return icsk->icsk_af_ops->getsockopt(sk, level, optname,
-                                                    optval, optlen);
-
        if (get_user(len, optlen))
                return -EFAULT;
 
@@ -2025,6 +2041,29 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
        return 0;
 }
 
+int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
+                  int __user *optlen)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (level != SOL_TCP)
+               return icsk->icsk_af_ops->getsockopt(sk, level, optname,
+                                                    optval, optlen);
+       return do_tcp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       if (level != SOL_TCP)
+               return inet_csk_compat_getsockopt(sk, level, optname,
+                                                 optval, optlen);
+       return do_tcp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL(compat_tcp_getsockopt);
+#endif
 
 extern void __skb_cb_too_small_for_tcp(int, int);
 extern struct tcp_congestion_ops tcp_reno;
index 128de4d..1b2ff53 100644 (file)
@@ -27,12 +27,12 @@ struct htcp {
        u16     alpha;          /* Fixed point arith, << 7 */
        u8      beta;           /* Fixed point arith, << 7 */
        u8      modeswitch;     /* Delay modeswitch until we had at least one congestion event */
-       u8      ccount;         /* Number of RTTs since last congestion event */
-       u8      undo_ccount;
-       u16     packetcount;
+       u32     last_cong;      /* Time since last congestion event end */
+       u32     undo_last_cong;
+       u16     pkts_acked;
+       u32     packetcount;
        u32     minRTT;
        u32     maxRTT;
-       u32     snd_cwnd_cnt2;
 
        u32     undo_maxRTT;
        u32     undo_old_maxB;
@@ -45,21 +45,30 @@ struct htcp {
        u32     lasttime;
 };
 
+static inline u32 htcp_cong_time(struct htcp *ca)
+{
+       return jiffies - ca->last_cong;
+}
+
+static inline u32 htcp_ccount(struct htcp *ca)
+{
+       return htcp_cong_time(ca)/ca->minRTT;
+}
+
 static inline void htcp_reset(struct htcp *ca)
 {
-       ca->undo_ccount = ca->ccount;
+       ca->undo_last_cong = ca->last_cong;
        ca->undo_maxRTT = ca->maxRTT;
        ca->undo_old_maxB = ca->old_maxB;
 
-       ca->ccount = 0;
-       ca->snd_cwnd_cnt2 = 0;
+       ca->last_cong = jiffies;
 }
 
 static u32 htcp_cwnd_undo(struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
        struct htcp *ca = inet_csk_ca(sk);
-       ca->ccount = ca->undo_ccount;
+       ca->last_cong = ca->undo_last_cong;
        ca->maxRTT = ca->undo_maxRTT;
        ca->old_maxB = ca->undo_old_maxB;
        return max(tp->snd_cwnd, (tp->snd_ssthresh<<7)/ca->beta);
@@ -77,10 +86,10 @@ static inline void measure_rtt(struct sock *sk)
                ca->minRTT = srtt;
 
        /* max RTT */
-       if (icsk->icsk_ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && ca->ccount > 3) {
+       if (icsk->icsk_ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && htcp_ccount(ca) > 3) {
                if (ca->maxRTT < ca->minRTT)
                        ca->maxRTT = ca->minRTT;
-               if (ca->maxRTT < srtt && srtt <= ca->maxRTT+HZ/50)
+               if (ca->maxRTT < srtt && srtt <= ca->maxRTT+msecs_to_jiffies(20))
                        ca->maxRTT = srtt;
        }
 }
@@ -92,6 +101,12 @@ static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked)
        struct htcp *ca = inet_csk_ca(sk);
        u32 now = tcp_time_stamp;
 
+       if (icsk->icsk_ca_state == TCP_CA_Open)
+               ca->pkts_acked = pkts_acked;
+
+       if (!use_bandwidth_switch)
+               return;
+
        /* achieved throughput calculations */
        if (icsk->icsk_ca_state != TCP_CA_Open &&
            icsk->icsk_ca_state != TCP_CA_Disorder) {
@@ -106,7 +121,7 @@ static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked)
                        && now - ca->lasttime >= ca->minRTT
                        && ca->minRTT > 0) {
                __u32 cur_Bi = ca->packetcount*HZ/(now - ca->lasttime);
-               if (ca->ccount <= 3) {
+               if (htcp_ccount(ca) <= 3) {
                        /* just after backoff */
                        ca->minB = ca->maxB = ca->Bi = cur_Bi;
                } else {
@@ -135,7 +150,7 @@ static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT)
                }
        }
 
-       if (ca->modeswitch && minRTT > max(HZ/100, 1) && maxRTT) {
+       if (ca->modeswitch && minRTT > msecs_to_jiffies(10) && maxRTT) {
                ca->beta = (minRTT<<7)/maxRTT;
                if (ca->beta < BETA_MIN)
                        ca->beta = BETA_MIN;
@@ -151,7 +166,7 @@ static inline void htcp_alpha_update(struct htcp *ca)
 {
        u32 minRTT = ca->minRTT;
        u32 factor = 1;
-       u32 diff = ca->ccount * minRTT; /* time since last backoff */
+       u32 diff = htcp_cong_time(ca);
 
        if (diff > HZ) {
                diff -= HZ;
@@ -216,21 +231,18 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
 
                measure_rtt(sk);
 
-               /* keep track of number of round-trip times since last backoff event */
-               if (ca->snd_cwnd_cnt2++ > tp->snd_cwnd) {
-                       ca->ccount++;
-                       ca->snd_cwnd_cnt2 = 0;
-                       htcp_alpha_update(ca);
-               }
-
                /* In dangerous area, increase slowly.
                 * In theory this is tp->snd_cwnd += alpha / tp->snd_cwnd
                 */
-               if ((tp->snd_cwnd_cnt++ * ca->alpha)>>7 >= tp->snd_cwnd) {
+               if ((tp->snd_cwnd_cnt * ca->alpha)>>7 >= tp->snd_cwnd) {
                        if (tp->snd_cwnd < tp->snd_cwnd_clamp)
                                tp->snd_cwnd++;
                        tp->snd_cwnd_cnt = 0;
-               }
+                       htcp_alpha_update(ca);
+               } else
+                       tp->snd_cwnd_cnt += ca->pkts_acked;
+
+               ca->pkts_acked = 1;
        }
 }
 
@@ -249,11 +261,19 @@ static void htcp_init(struct sock *sk)
        memset(ca, 0, sizeof(struct htcp));
        ca->alpha = ALPHA_BASE;
        ca->beta = BETA_MIN;
+       ca->pkts_acked = 1;
+       ca->last_cong = jiffies;
 }
 
 static void htcp_state(struct sock *sk, u8 new_state)
 {
        switch (new_state) {
+       case TCP_CA_Open:
+               {
+                       struct htcp *ca = inet_csk_ca(sk);
+                       ca->last_cong = jiffies;
+               }
+               break;
        case TCP_CA_CWR:
        case TCP_CA_Recovery:
        case TCP_CA_Loss:
@@ -278,8 +298,6 @@ static int __init htcp_register(void)
 {
        BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE);
        BUILD_BUG_ON(BETA_MIN >= BETA_MAX);
-       if (!use_bandwidth_switch)
-               htcp.pkts_acked = NULL;
        return tcp_register_congestion_control(&htcp);
 }
 
index e9a54ae..195d835 100644 (file)
@@ -1891,6 +1891,34 @@ static void tcp_try_to_open(struct sock *sk, struct tcp_sock *tp, int flag)
        }
 }
 
+static void tcp_mtup_probe_failed(struct sock *sk)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       icsk->icsk_mtup.search_high = icsk->icsk_mtup.probe_size - 1;
+       icsk->icsk_mtup.probe_size = 0;
+}
+
+static void tcp_mtup_probe_success(struct sock *sk, struct sk_buff *skb)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       /* FIXME: breaks with very large cwnd */
+       tp->prior_ssthresh = tcp_current_ssthresh(sk);
+       tp->snd_cwnd = tp->snd_cwnd *
+                      tcp_mss_to_mtu(sk, tp->mss_cache) /
+                      icsk->icsk_mtup.probe_size;
+       tp->snd_cwnd_cnt = 0;
+       tp->snd_cwnd_stamp = tcp_time_stamp;
+       tp->rcv_ssthresh = tcp_current_ssthresh(sk);
+
+       icsk->icsk_mtup.search_low = icsk->icsk_mtup.probe_size;
+       icsk->icsk_mtup.probe_size = 0;
+       tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+}
+
+
 /* Process an event, which can update packets-in-flight not trivially.
  * Main goal of this function is to calculate new estimate for left_out,
  * taking into account both packets sitting in receiver's buffer and
@@ -2023,6 +2051,17 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
                        return;
                }
 
+               /* MTU probe failure: don't reduce cwnd */
+               if (icsk->icsk_ca_state < TCP_CA_CWR &&
+                   icsk->icsk_mtup.probe_size &&
+                   tp->snd_una == tp->mtu_probe.probe_seq_start) {
+                       tcp_mtup_probe_failed(sk);
+                       /* Restores the reduction we did in tcp_mtup_probe() */
+                       tp->snd_cwnd++;
+                       tcp_simple_retransmit(sk);
+                       return;
+               }
+
                /* Otherwise enter Recovery state */
 
                if (IsReno(tp))
@@ -2243,6 +2282,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
                        tp->retrans_stamp = 0;
                }
 
+               /* MTU probing checks */
+               if (icsk->icsk_mtup.probe_size) {
+                       if (!after(tp->mtu_probe.probe_seq_end, TCP_SKB_CB(skb)->end_seq)) {
+                               tcp_mtup_probe_success(sk, skb);
+                       }
+               }
+
                if (sacked) {
                        if (sacked & TCPCB_RETRANS) {
                                if(sacked & TCPCB_SACKED_RETRANS)
@@ -4101,6 +4147,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
                if (tp->rx_opt.sack_ok && sysctl_tcp_fack)
                        tp->rx_opt.sack_ok |= 2;
 
+               tcp_mtup_init(sk);
                tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
                tcp_initialize_rcv_mss(sk);
 
@@ -4211,6 +4258,7 @@ discard:
                if (tp->ecn_flags&TCP_ECN_OK)
                        sock_set_flag(sk, SOCK_NO_LARGESEND);
 
+               tcp_mtup_init(sk);
                tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
                tcp_initialize_rcv_mss(sk);
 
@@ -4399,6 +4447,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                 */
                                tp->lsndtime = tcp_time_stamp;
 
+                               tcp_mtup_init(sk);
                                tcp_initialize_rcv_mss(sk);
                                tcp_init_buffer_space(sk);
                                tcp_fast_path_on(tp);
index 233bdf2..9e85c04 100644 (file)
@@ -900,6 +900,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen;
        newinet->id = newtp->write_seq ^ jiffies;
 
+       tcp_mtup_init(newsk);
        tcp_sync_mss(newsk, dst_mtu(dst));
        newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
        tcp_initialize_rcv_mss(newsk);
@@ -1216,17 +1217,21 @@ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
 }
 
 struct inet_connection_sock_af_ops ipv4_specific = {
-       .queue_xmit     =       ip_queue_xmit,
-       .send_check     =       tcp_v4_send_check,
-       .rebuild_header =       inet_sk_rebuild_header,
-       .conn_request   =       tcp_v4_conn_request,
-       .syn_recv_sock  =       tcp_v4_syn_recv_sock,
-       .remember_stamp =       tcp_v4_remember_stamp,
-       .net_header_len =       sizeof(struct iphdr),
-       .setsockopt     =       ip_setsockopt,
-       .getsockopt     =       ip_getsockopt,
-       .addr2sockaddr  =       inet_csk_addr2sockaddr,
-       .sockaddr_len   =       sizeof(struct sockaddr_in),
+       .queue_xmit        = ip_queue_xmit,
+       .send_check        = tcp_v4_send_check,
+       .rebuild_header    = inet_sk_rebuild_header,
+       .conn_request      = tcp_v4_conn_request,
+       .syn_recv_sock     = tcp_v4_syn_recv_sock,
+       .remember_stamp    = tcp_v4_remember_stamp,
+       .net_header_len    = sizeof(struct iphdr),
+       .setsockopt        = ip_setsockopt,
+       .getsockopt        = ip_getsockopt,
+       .addr2sockaddr     = inet_csk_addr2sockaddr,
+       .sockaddr_len      = sizeof(struct sockaddr_in),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ip_setsockopt,
+       .compat_getsockopt = compat_ip_getsockopt,
+#endif
 };
 
 /* NOTE: A lot of things set to zero explicitly by call to
@@ -1825,23 +1830,16 @@ struct proto tcp_prot = {
        .obj_size               = sizeof(struct tcp_sock),
        .twsk_prot              = &tcp_timewait_sock_ops,
        .rsk_prot               = &tcp_request_sock_ops,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt      = compat_tcp_setsockopt,
+       .compat_getsockopt      = compat_tcp_getsockopt,
+#endif
 };
 
-
-
 void __init tcp_v4_init(struct net_proto_family *ops)
 {
-       int err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket);
-       if (err < 0)
+       if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, IPPROTO_TCP) < 0)
                panic("Failed to create the TCP control socket.\n");
-       tcp_socket->sk->sk_allocation   = GFP_ATOMIC;
-       inet_sk(tcp_socket->sk)->uc_ttl = -1;
-
-       /* Unhash it so that IP input processing does not even
-        * see it, we do not wish this socket to see incoming
-        * packets.
-        */
-       tcp_socket->sk->sk_prot->unhash(tcp_socket->sk);
 }
 
 EXPORT_SYMBOL(ipv4_specific);
index 9f498a6..9d79546 100644 (file)
 /* People can turn this off for buggy TCP's found in printers etc. */
 int sysctl_tcp_retrans_collapse = 1;
 
+/* People can turn this on to  work with those rare, broken TCPs that
+ * interpret the window field as a signed quantity.
+ */
+int sysctl_tcp_workaround_signed_windows = 0;
+
 /* This limits the percentage of the congestion window which we
  * will allow a single TSO frame to consume.  Building TSO frames
  * which are too large can cause TCP streams to be bursty.
  */
 int sysctl_tcp_tso_win_divisor = 3;
 
+int sysctl_tcp_mtu_probing = 0;
+int sysctl_tcp_base_mss = 512;
+
+EXPORT_SYMBOL(sysctl_tcp_mtu_probing);
+EXPORT_SYMBOL(sysctl_tcp_base_mss);
+
 static void update_send_head(struct sock *sk, struct tcp_sock *tp,
                             struct sk_buff *skb)
 {
@@ -171,12 +182,18 @@ void tcp_select_initial_window(int __space, __u32 mss,
                space = (space / mss) * mss;
 
        /* NOTE: offering an initial window larger than 32767
-        * will break some buggy TCP stacks. We try to be nice.
-        * If we are not window scaling, then this truncates
-        * our initial window offering to 32k. There should also
-        * be a sysctl option to stop being nice.
+        * will break some buggy TCP stacks. If the admin tells us
+        * it is likely we could be speaking with such a buggy stack
+        * we will truncate our initial window offering to 32K-1
+        * unless the remote has sent us a window scaling option,
+        * which we interpret as a sign the remote TCP is not
+        * misinterpreting the window field as a signed quantity.
         */
-       (*rcv_wnd) = min(space, MAX_TCP_WINDOW);
+       if (sysctl_tcp_workaround_signed_windows)
+               (*rcv_wnd) = min(space, MAX_TCP_WINDOW);
+       else
+               (*rcv_wnd) = space;
+
        (*rcv_wscale) = 0;
        if (wscale_ok) {
                /* Set window scaling on max possible window
@@ -235,7 +252,7 @@ static u16 tcp_select_window(struct sock *sk)
        /* Make sure we do not exceed the maximum possible
         * scaled window.
         */
-       if (!tp->rx_opt.rcv_wscale)
+       if (!tp->rx_opt.rcv_wscale && sysctl_tcp_workaround_signed_windows)
                new_win = min(new_win, MAX_TCP_WINDOW);
        else
                new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale));
@@ -681,6 +698,62 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
        return 0;
 }
 
+/* Not accounting for SACKs here. */
+int tcp_mtu_to_mss(struct sock *sk, int pmtu)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       int mss_now;
+
+       /* Calculate base mss without TCP options:
+          It is MMS_S - sizeof(tcphdr) of rfc1122
+        */
+       mss_now = pmtu - icsk->icsk_af_ops->net_header_len - sizeof(struct tcphdr);
+
+       /* Clamp it (mss_clamp does not include tcp options) */
+       if (mss_now > tp->rx_opt.mss_clamp)
+               mss_now = tp->rx_opt.mss_clamp;
+
+       /* Now subtract optional transport overhead */
+       mss_now -= icsk->icsk_ext_hdr_len;
+
+       /* Then reserve room for full set of TCP options and 8 bytes of data */
+       if (mss_now < 48)
+               mss_now = 48;
+
+       /* Now subtract TCP options size, not including SACKs */
+       mss_now -= tp->tcp_header_len - sizeof(struct tcphdr);
+
+       return mss_now;
+}
+
+/* Inverse of above */
+int tcp_mss_to_mtu(struct sock *sk, int mss)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       int mtu;
+
+       mtu = mss +
+             tp->tcp_header_len +
+             icsk->icsk_ext_hdr_len +
+             icsk->icsk_af_ops->net_header_len;
+
+       return mtu;
+}
+
+void tcp_mtup_init(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       icsk->icsk_mtup.enabled = sysctl_tcp_mtu_probing > 1;
+       icsk->icsk_mtup.search_high = tp->rx_opt.mss_clamp + sizeof(struct tcphdr) +
+                              icsk->icsk_af_ops->net_header_len;
+       icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, sysctl_tcp_base_mss);
+       icsk->icsk_mtup.probe_size = 0;
+}
+
 /* This function synchronize snd mss to current pmtu/exthdr set.
 
    tp->rx_opt.user_mss is mss set by user by TCP_MAXSEG. It does NOT counts
@@ -708,25 +781,12 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
-       /* Calculate base mss without TCP options:
-          It is MMS_S - sizeof(tcphdr) of rfc1122
-        */
-       int mss_now = (pmtu - icsk->icsk_af_ops->net_header_len -
-                      sizeof(struct tcphdr));
-
-       /* Clamp it (mss_clamp does not include tcp options) */
-       if (mss_now > tp->rx_opt.mss_clamp)
-               mss_now = tp->rx_opt.mss_clamp;
-
-       /* Now subtract optional transport overhead */
-       mss_now -= icsk->icsk_ext_hdr_len;
+       int mss_now;
 
-       /* Then reserve room for full set of TCP options and 8 bytes of data */
-       if (mss_now < 48)
-               mss_now = 48;
+       if (icsk->icsk_mtup.search_high > pmtu)
+               icsk->icsk_mtup.search_high = pmtu;
 
-       /* Now subtract TCP options size, not including SACKs */
-       mss_now -= tp->tcp_header_len - sizeof(struct tcphdr);
+       mss_now = tcp_mtu_to_mss(sk, pmtu);
 
        /* Bound mss with half of window */
        if (tp->max_window && mss_now > (tp->max_window>>1))
@@ -734,6 +794,8 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
 
        /* And store cached results */
        icsk->icsk_pmtu_cookie = pmtu;
+       if (icsk->icsk_mtup.enabled)
+               mss_now = min(mss_now, tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low));
        tp->mss_cache = mss_now;
 
        return mss_now;
@@ -1063,6 +1125,140 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
        return 1;
 }
 
+/* Create a new MTU probe if we are ready.
+ * Returns 0 if we should wait to probe (no cwnd available),
+ *         1 if a probe was sent,
+ *         -1 otherwise */
+static int tcp_mtu_probe(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct sk_buff *skb, *nskb, *next;
+       int len;
+       int probe_size;
+       unsigned int pif;
+       int copy;
+       int mss_now;
+
+       /* Not currently probing/verifying,
+        * not in recovery,
+        * have enough cwnd, and
+        * not SACKing (the variable headers throw things off) */
+       if (!icsk->icsk_mtup.enabled ||
+           icsk->icsk_mtup.probe_size ||
+           inet_csk(sk)->icsk_ca_state != TCP_CA_Open ||
+           tp->snd_cwnd < 11 ||
+           tp->rx_opt.eff_sacks)
+               return -1;
+
+       /* Very simple search strategy: just double the MSS. */
+       mss_now = tcp_current_mss(sk, 0);
+       probe_size = 2*tp->mss_cache;
+       if (probe_size > tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_high)) {
+               /* TODO: set timer for probe_converge_event */
+               return -1;
+       }
+
+       /* Have enough data in the send queue to probe? */
+       len = 0;
+       if ((skb = sk->sk_send_head) == NULL)
+               return -1;
+       while ((len += skb->len) < probe_size && !tcp_skb_is_last(sk, skb))
+               skb = skb->next;
+       if (len < probe_size)
+               return -1;
+
+       /* Receive window check. */
+       if (after(TCP_SKB_CB(skb)->seq + probe_size, tp->snd_una + tp->snd_wnd)) {
+               if (tp->snd_wnd < probe_size)
+                       return -1;
+               else
+                       return 0;
+       }
+
+       /* Do we need to wait to drain cwnd? */
+       pif = tcp_packets_in_flight(tp);
+       if (pif + 2 > tp->snd_cwnd) {
+               /* With no packets in flight, don't stall. */
+               if (pif == 0)
+                       return -1;
+               else
+                       return 0;
+       }
+
+       /* We're allowed to probe.  Build it now. */
+       if ((nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC)) == NULL)
+               return -1;
+       sk_charge_skb(sk, nskb);
+
+       skb = sk->sk_send_head;
+       __skb_insert(nskb, skb->prev, skb, &sk->sk_write_queue);
+       sk->sk_send_head = nskb;
+
+       TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
+       TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
+       TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK;
+       TCP_SKB_CB(nskb)->sacked = 0;
+       nskb->csum = 0;
+       if (skb->ip_summed == CHECKSUM_HW)
+               nskb->ip_summed = CHECKSUM_HW;
+
+       len = 0;
+       while (len < probe_size) {
+               next = skb->next;
+
+               copy = min_t(int, skb->len, probe_size - len);
+               if (nskb->ip_summed)
+                       skb_copy_bits(skb, 0, skb_put(nskb, copy), copy);
+               else
+                       nskb->csum = skb_copy_and_csum_bits(skb, 0,
+                                        skb_put(nskb, copy), copy, nskb->csum);
+
+               if (skb->len <= copy) {
+                       /* We've eaten all the data from this skb.
+                        * Throw it away. */
+                       TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags;
+                       __skb_unlink(skb, &sk->sk_write_queue);
+                       sk_stream_free_skb(sk, skb);
+               } else {
+                       TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags &
+                                                  ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
+                       if (!skb_shinfo(skb)->nr_frags) {
+                               skb_pull(skb, copy);
+                               if (skb->ip_summed != CHECKSUM_HW)
+                                       skb->csum = csum_partial(skb->data, skb->len, 0);
+                       } else {
+                               __pskb_trim_head(skb, copy);
+                               tcp_set_skb_tso_segs(sk, skb, mss_now);
+                       }
+                       TCP_SKB_CB(skb)->seq += copy;
+               }
+
+               len += copy;
+               skb = next;
+       }
+       tcp_init_tso_segs(sk, nskb, nskb->len);
+
+       /* We're ready to send.  If this fails, the probe will
+        * be resegmented into mss-sized pieces by tcp_write_xmit(). */
+       TCP_SKB_CB(nskb)->when = tcp_time_stamp;
+       if (!tcp_transmit_skb(sk, nskb, 1, GFP_ATOMIC)) {
+               /* Decrement cwnd here because we are sending
+               * effectively two packets. */
+               tp->snd_cwnd--;
+               update_send_head(sk, tp, nskb);
+
+               icsk->icsk_mtup.probe_size = tcp_mss_to_mtu(sk, nskb->len);
+               tp->mtu_probe.probe_seq_start = TCP_SKB_CB(nskb)->seq;
+               tp->mtu_probe.probe_seq_end = TCP_SKB_CB(nskb)->end_seq;
+
+               return 1;
+       }
+
+       return -1;
+}
+
+
 /* This routine writes packets to the network.  It advances the
  * send_head.  This happens as incoming acks open up the remote
  * window for us.
@@ -1076,6 +1272,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
        struct sk_buff *skb;
        unsigned int tso_segs, sent_pkts;
        int cwnd_quota;
+       int result;
 
        /* If we are closed, the bytes will have to remain here.
         * In time closedown will finish, we empty the write queue and all
@@ -1085,6 +1282,14 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
                return 0;
 
        sent_pkts = 0;
+
+       /* Do MTU probing. */
+       if ((result = tcp_mtu_probe(sk)) == 0) {
+               return 0;
+       } else if (result > 0) {
+               sent_pkts = 1;
+       }
+
        while ((skb = sk->sk_send_head)) {
                unsigned int limit;
 
@@ -1455,9 +1660,15 @@ void tcp_simple_retransmit(struct sock *sk)
 int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
        unsigned int cur_mss = tcp_current_mss(sk, 0);
        int err;
 
+       /* Inconslusive MTU probe */
+       if (icsk->icsk_mtup.probe_size) {
+               icsk->icsk_mtup.probe_size = 0;
+       }
+
        /* Do not sent more than we queued. 1/4 is reserved for possible
         * copying overhead: fragmentation, tunneling, mangling etc.
         */
@@ -1883,6 +2094,7 @@ static void tcp_connect_init(struct sock *sk)
        if (tp->rx_opt.user_mss)
                tp->rx_opt.mss_clamp = tp->rx_opt.user_mss;
        tp->max_window = 0;
+       tcp_mtup_init(sk);
        tcp_sync_mss(sk, dst_mtu(dst));
 
        if (!tp->window_clamp)
@@ -2180,3 +2392,4 @@ EXPORT_SYMBOL(tcp_make_synack);
 EXPORT_SYMBOL(tcp_simple_retransmit);
 EXPORT_SYMBOL(tcp_sync_mss);
 EXPORT_SYMBOL(sysctl_tcp_tso_win_divisor);
+EXPORT_SYMBOL(tcp_mtup_init);
index e188095..7c1bde3 100644 (file)
@@ -119,8 +119,10 @@ static int tcp_orphan_retries(struct sock *sk, int alive)
 /* A write timeout has occurred. Process the after effects. */
 static int tcp_write_timeout(struct sock *sk)
 {
-       const struct inet_connection_sock *icsk = inet_csk(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       struct tcp_sock *tp = tcp_sk(sk);
        int retry_until;
+       int mss;
 
        if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
                if (icsk->icsk_retransmits)
@@ -128,25 +130,19 @@ static int tcp_write_timeout(struct sock *sk)
                retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
        } else {
                if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
-                       /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black
-                          hole detection. :-(
-
-                          It is place to make it. It is not made. I do not want
-                          to make it. It is disgusting. It does not work in any
-                          case. Let me to cite the same draft, which requires for
-                          us to implement this:
-
-   "The one security concern raised by this memo is that ICMP black holes
-   are often caused by over-zealous security administrators who block
-   all ICMP messages.  It is vitally important that those who design and
-   deploy security systems understand the impact of strict filtering on
-   upper-layer protocols.  The safest web site in the world is worthless
-   if most TCP implementations cannot transfer data from it.  It would
-   be far nicer to have all of the black holes fixed rather than fixing
-   all of the TCP implementations."
-
-                           Golden words :-).
-                  */
+                       /* Black hole detection */
+                       if (sysctl_tcp_mtu_probing) {
+                               if (!icsk->icsk_mtup.enabled) {
+                                       icsk->icsk_mtup.enabled = 1;
+                                       tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+                               } else {
+                                       mss = min(sysctl_tcp_base_mss,
+                                                 tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low)/2);
+                                       mss = max(mss, 68 - tp->tcp_header_len);
+                                       icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss);
+                                       tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
+                               }
+                       }
 
                        dst_negative_advice(&sk->sk_dst_cache);
                }
index 0084047..3f93292 100644 (file)
@@ -1207,16 +1207,13 @@ static int udp_destroy_sock(struct sock *sk)
 /*
  *     Socket option code for UDP
  */
-static int udp_setsockopt(struct sock *sk, int level, int optname, 
+static int do_udp_setsockopt(struct sock *sk, int level, int optname,
                          char __user *optval, int optlen)
 {
        struct udp_sock *up = udp_sk(sk);
        int val;
        int err = 0;
 
-       if (level != SOL_UDP)
-               return ip_setsockopt(sk, level, optname, optval, optlen);
-
        if(optlen<sizeof(int))
                return -EINVAL;
 
@@ -1256,15 +1253,30 @@ static int udp_setsockopt(struct sock *sk, int level, int optname,
        return err;
 }
 
-static int udp_getsockopt(struct sock *sk, int level, int optname, 
+static int udp_setsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int optlen)
+{
+       if (level != SOL_UDP)
+               return ip_setsockopt(sk, level, optname, optval, optlen);
+       return do_udp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_udp_setsockopt(struct sock *sk, int level, int optname,
+                                char __user *optval, int optlen)
+{
+       if (level != SOL_UDP)
+               return compat_ip_setsockopt(sk, level, optname, optval, optlen);
+       return do_udp_setsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
+static int do_udp_getsockopt(struct sock *sk, int level, int optname,
                          char __user *optval, int __user *optlen)
 {
        struct udp_sock *up = udp_sk(sk);
        int val, len;
 
-       if (level != SOL_UDP)
-               return ip_getsockopt(sk, level, optname, optval, optlen);
-
        if(get_user(len,optlen))
                return -EFAULT;
 
@@ -1293,6 +1305,23 @@ static int udp_getsockopt(struct sock *sk, int level, int optname,
        return 0;
 }
 
+static int udp_getsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       if (level != SOL_UDP)
+               return ip_getsockopt(sk, level, optname, optval, optlen);
+       return do_udp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_udp_getsockopt(struct sock *sk, int level, int optname,
+                                char __user *optval, int __user *optlen)
+{
+       if (level != SOL_UDP)
+               return compat_ip_getsockopt(sk, level, optname, optval, optlen);
+       return do_udp_getsockopt(sk, level, optname, optval, optlen);
+}
+#endif
 /**
  *     udp_poll - wait for a UDP event.
  *     @file - file struct
@@ -1341,23 +1370,27 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
 }
 
 struct proto udp_prot = {
-       .name =         "UDP",
-       .owner =        THIS_MODULE,
-       .close =        udp_close,
-       .connect =      ip4_datagram_connect,
-       .disconnect =   udp_disconnect,
-       .ioctl =        udp_ioctl,
-       .destroy =      udp_destroy_sock,
-       .setsockopt =   udp_setsockopt,
-       .getsockopt =   udp_getsockopt,
-       .sendmsg =      udp_sendmsg,
-       .recvmsg =      udp_recvmsg,
-       .sendpage =     udp_sendpage,
-       .backlog_rcv =  udp_queue_rcv_skb,
-       .hash =         udp_v4_hash,
-       .unhash =       udp_v4_unhash,
-       .get_port =     udp_v4_get_port,
-       .obj_size =     sizeof(struct udp_sock),
+       .name              = "UDP",
+       .owner             = THIS_MODULE,
+       .close             = udp_close,
+       .connect           = ip4_datagram_connect,
+       .disconnect        = udp_disconnect,
+       .ioctl             = udp_ioctl,
+       .destroy           = udp_destroy_sock,
+       .setsockopt        = udp_setsockopt,
+       .getsockopt        = udp_getsockopt,
+       .sendmsg           = udp_sendmsg,
+       .recvmsg           = udp_recvmsg,
+       .sendpage          = udp_sendpage,
+       .backlog_rcv       = udp_queue_rcv_skb,
+       .hash              = udp_v4_hash,
+       .unhash            = udp_v4_unhash,
+       .get_port          = udp_v4_get_port,
+       .obj_size          = sizeof(struct udp_sock),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_udp_setsockopt,
+       .compat_getsockopt = compat_udp_getsockopt,
+#endif
 };
 
 /* ------------------------------------------------------------------------ */
index afbb0d4..b08d56b 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/skbuff.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -26,19 +27,19 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, s
 }
 
 static struct xfrm_tunnel *ipip_handler;
-static DECLARE_MUTEX(xfrm4_tunnel_sem);
+static DEFINE_MUTEX(xfrm4_tunnel_mutex);
 
 int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
 {
        int ret;
 
-       down(&xfrm4_tunnel_sem);
+       mutex_lock(&xfrm4_tunnel_mutex);
        ret = 0;
        if (ipip_handler != NULL)
                ret = -EINVAL;
        if (!ret)
                ipip_handler = handler;
-       up(&xfrm4_tunnel_sem);
+       mutex_unlock(&xfrm4_tunnel_mutex);
 
        return ret;
 }
@@ -49,13 +50,13 @@ int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler)
 {
        int ret;
 
-       down(&xfrm4_tunnel_sem);
+       mutex_lock(&xfrm4_tunnel_mutex);
        ret = 0;
        if (ipip_handler != handler)
                ret = -EINVAL;
        if (!ret)
                ipip_handler = NULL;
-       up(&xfrm4_tunnel_sem);
+       mutex_unlock(&xfrm4_tunnel_mutex);
 
        synchronize_net();
 
index ab7a912..e6f83b6 100644 (file)
@@ -6,8 +6,6 @@
 config IPV6
        tristate "The IPv6 protocol"
        default m
-       select CRYPTO if IPV6_PRIVACY
-       select CRYPTO_MD5 if IPV6_PRIVACY
        ---help---
          This is complemental support for the IP version 6.
          You will still be able to do traditional IPv4 networking as well.
@@ -22,7 +20,7 @@ config IPV6
          module will be called ipv6.
 
 config IPV6_PRIVACY
-       bool "IPv6: Privacy Extensions (RFC 3041) support"
+       bool "IPv6: Privacy Extensions support"
        depends on IPV6
        ---help---
          Privacy Extensions for Stateless Address Autoconfiguration in IPv6
@@ -30,6 +28,9 @@ config IPV6_PRIVACY
          pseudo-random global-scope unicast address(es) will assigned to
          your interface(s).
        
+         We use our standard pseudo random algorithm to generate randomized
+         interface identifier, instead of one described in RFC 3041.
+
          By default, kernel do not generate temporary addresses.
          To use temporary addresses, do
        
@@ -37,6 +38,25 @@ config IPV6_PRIVACY
 
          See <file:Documentation/networking/ip-sysctl.txt> for details.
 
+config IPV6_ROUTER_PREF
+       bool "IPv6: Router Preference (RFC 4191) support"
+       depends on IPV6
+       ---help---
+         Router Preference is an optional extension to the Router
+         Advertisement message to improve the ability of hosts
+         to pick more appropriate router, especially when the hosts
+         is placed in a multi-homed network.
+
+         If unsure, say N.
+
+config IPV6_ROUTE_INFO
+       bool "IPv6: Route Information (RFC 4191) support (EXPERIMENTAL)"
+       depends on IPV6_ROUTER_PREF && EXPERIMENTAL
+       ---help---
+         This is experimental support of Route Information.
+
+         If unsure, say N.
+
 config INET6_AH
        tristate "IPv6: AH transformation"
        depends on IPV6
index 19727d9..01c62a0 100644 (file)
@@ -78,8 +78,6 @@
 
 #ifdef CONFIG_IPV6_PRIVACY
 #include <linux/random.h>
-#include <linux/crypto.h>
-#include <linux/scatterlist.h>
 #endif
 
 #include <asm/uaccess.h>
@@ -110,8 +108,6 @@ static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpad
 static void ipv6_regen_rndid(unsigned long data);
 
 static int desync_factor = MAX_DESYNC_FACTOR * HZ;
-static struct crypto_tfm *md5_tfm;
-static DEFINE_SPINLOCK(md5_tfm_lock);
 #endif
 
 static int ipv6_count_addresses(struct inet6_dev *idev);
@@ -169,6 +165,15 @@ struct ipv6_devconf ipv6_devconf = {
        .max_desync_factor      = MAX_DESYNC_FACTOR,
 #endif
        .max_addresses          = IPV6_MAX_ADDRESSES,
+       .accept_ra_defrtr       = 1,
+       .accept_ra_pinfo        = 1,
+#ifdef CONFIG_IPV6_ROUTER_PREF
+       .accept_ra_rtr_pref     = 1,
+       .rtr_probe_interval     = 60 * HZ,
+#ifdef CONFIG_IPV6_ROUTE_INFO
+       .accept_ra_rt_info_max_plen = 0,
+#endif
+#endif
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt = {
@@ -190,6 +195,15 @@ static struct ipv6_devconf ipv6_devconf_dflt = {
        .max_desync_factor      = MAX_DESYNC_FACTOR,
 #endif
        .max_addresses          = IPV6_MAX_ADDRESSES,
+       .accept_ra_defrtr       = 1,
+       .accept_ra_pinfo        = 1,
+#ifdef CONFIG_IPV6_ROUTER_PREF
+       .accept_ra_rtr_pref     = 1,
+       .rtr_probe_interval     = 60 * HZ,
+#ifdef CONFIG_IPV6_ROUTE_INFO
+       .accept_ra_rt_info_max_plen = 0,
+#endif
+#endif
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -327,86 +341,83 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
        if (dev->mtu < IPV6_MIN_MTU)
                return NULL;
 
-       ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL);
+       ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL);
 
-       if (ndev) {
-               memset(ndev, 0, sizeof(struct inet6_dev));
+       if (ndev == NULL)
+               return NULL;
 
-               rwlock_init(&ndev->lock);
-               ndev->dev = dev;
-               memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
-               ndev->cnf.mtu6 = dev->mtu;
-               ndev->cnf.sysctl = NULL;
-               ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
-               if (ndev->nd_parms == NULL) {
-                       kfree(ndev);
-                       return NULL;
-               }
-               /* We refer to the device */
-               dev_hold(dev);
-
-               if (snmp6_alloc_dev(ndev) < 0) {
-                       ADBG((KERN_WARNING
-                               "%s(): cannot allocate memory for statistics; dev=%s.\n",
-                               __FUNCTION__, dev->name));
-                       neigh_parms_release(&nd_tbl, ndev->nd_parms);
-                       ndev->dead = 1;
-                       in6_dev_finish_destroy(ndev);
-                       return NULL;
-               }
+       rwlock_init(&ndev->lock);
+       ndev->dev = dev;
+       memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
+       ndev->cnf.mtu6 = dev->mtu;
+       ndev->cnf.sysctl = NULL;
+       ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
+       if (ndev->nd_parms == NULL) {
+               kfree(ndev);
+               return NULL;
+       }
+       /* We refer to the device */
+       dev_hold(dev);
 
-               if (snmp6_register_dev(ndev) < 0) {
-                       ADBG((KERN_WARNING
-                               "%s(): cannot create /proc/net/dev_snmp6/%s\n",
-                               __FUNCTION__, dev->name));
-                       neigh_parms_release(&nd_tbl, ndev->nd_parms);
-                       ndev->dead = 1;
-                       in6_dev_finish_destroy(ndev);
-                       return NULL;
-               }
+       if (snmp6_alloc_dev(ndev) < 0) {
+               ADBG((KERN_WARNING
+                       "%s(): cannot allocate memory for statistics; dev=%s.\n",
+                       __FUNCTION__, dev->name));
+               neigh_parms_release(&nd_tbl, ndev->nd_parms);
+               ndev->dead = 1;
+               in6_dev_finish_destroy(ndev);
+               return NULL;
+       }
 
-               /* One reference from device.  We must do this before
-                * we invoke __ipv6_regen_rndid().
-                */
-               in6_dev_hold(ndev);
+       if (snmp6_register_dev(ndev) < 0) {
+               ADBG((KERN_WARNING
+                       "%s(): cannot create /proc/net/dev_snmp6/%s\n",
+                       __FUNCTION__, dev->name));
+               neigh_parms_release(&nd_tbl, ndev->nd_parms);
+               ndev->dead = 1;
+               in6_dev_finish_destroy(ndev);
+               return NULL;
+       }
+
+       /* One reference from device.  We must do this before
+        * we invoke __ipv6_regen_rndid().
+        */
+       in6_dev_hold(ndev);
 
 #ifdef CONFIG_IPV6_PRIVACY
-               get_random_bytes(ndev->rndid, sizeof(ndev->rndid));
-               get_random_bytes(ndev->entropy, sizeof(ndev->entropy));
-               init_timer(&ndev->regen_timer);
-               ndev->regen_timer.function = ipv6_regen_rndid;
-               ndev->regen_timer.data = (unsigned long) ndev;
-               if ((dev->flags&IFF_LOOPBACK) ||
-                   dev->type == ARPHRD_TUNNEL ||
-                   dev->type == ARPHRD_NONE ||
-                   dev->type == ARPHRD_SIT) {
-                       printk(KERN_INFO
-                              "%s: Disabled Privacy Extensions\n",
-                              dev->name);
-                       ndev->cnf.use_tempaddr = -1;
-               } else {
-                       in6_dev_hold(ndev);
-                       ipv6_regen_rndid((unsigned long) ndev);
-               }
+       init_timer(&ndev->regen_timer);
+       ndev->regen_timer.function = ipv6_regen_rndid;
+       ndev->regen_timer.data = (unsigned long) ndev;
+       if ((dev->flags&IFF_LOOPBACK) ||
+           dev->type == ARPHRD_TUNNEL ||
+           dev->type == ARPHRD_NONE ||
+           dev->type == ARPHRD_SIT) {
+               printk(KERN_INFO
+                      "%s: Disabled Privacy Extensions\n",
+                      dev->name);
+               ndev->cnf.use_tempaddr = -1;
+       } else {
+               in6_dev_hold(ndev);
+               ipv6_regen_rndid((unsigned long) ndev);
+       }
 #endif
 
-               if (netif_carrier_ok(dev))
-                       ndev->if_flags |= IF_READY;
+       if (netif_carrier_ok(dev))
+               ndev->if_flags |= IF_READY;
 
-               write_lock_bh(&addrconf_lock);
-               dev->ip6_ptr = ndev;
-               write_unlock_bh(&addrconf_lock);
+       write_lock_bh(&addrconf_lock);
+       dev->ip6_ptr = ndev;
+       write_unlock_bh(&addrconf_lock);
 
-               ipv6_mc_init_dev(ndev);
-               ndev->tstamp = jiffies;
+       ipv6_mc_init_dev(ndev);
+       ndev->tstamp = jiffies;
 #ifdef CONFIG_SYSCTL
-               neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, 
-                                     NET_IPV6_NEIGH, "ipv6",
-                                     &ndisc_ifinfo_sysctl_change,
-                                     NULL);
-               addrconf_sysctl_register(ndev, &ndev->cnf);
+       neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6,
+                             NET_IPV6_NEIGH, "ipv6",
+                             &ndisc_ifinfo_sysctl_change,
+                             NULL);
+       addrconf_sysctl_register(ndev, &ndev->cnf);
 #endif
-       }
        return ndev;
 }
 
@@ -524,7 +535,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out;
        }
 
-       ifa = kmalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
+       ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
 
        if (ifa == NULL) {
                ADBG(("ipv6_add_addr: malloc failed\n"));
@@ -538,7 +549,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out;
        }
 
-       memset(ifa, 0, sizeof(struct inet6_ifaddr));
        ipv6_addr_copy(&ifa->addr, addr);
 
        spin_lock_init(&ifa->lock);
@@ -1305,52 +1315,67 @@ static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
        __ipv6_dev_ac_dec(ifp->idev, &addr);
 }
 
+static int addrconf_ifid_eui48(u8 *eui, struct net_device *dev)
+{
+       if (dev->addr_len != ETH_ALEN)
+               return -1;
+       memcpy(eui, dev->dev_addr, 3);
+       memcpy(eui + 5, dev->dev_addr + 3, 3);
+
+       /*
+        * The zSeries OSA network cards can be shared among various
+        * OS instances, but the OSA cards have only one MAC address.
+        * This leads to duplicate address conflicts in conjunction
+        * with IPv6 if more than one instance uses the same card.
+        *
+        * The driver for these cards can deliver a unique 16-bit
+        * identifier for each instance sharing the same card.  It is
+        * placed instead of 0xFFFE in the interface identifier.  The
+        * "u" bit of the interface identifier is not inverted in this
+        * case.  Hence the resulting interface identifier has local
+        * scope according to RFC2373.
+        */
+       if (dev->dev_id) {
+               eui[3] = (dev->dev_id >> 8) & 0xFF;
+               eui[4] = dev->dev_id & 0xFF;
+       } else {
+               eui[3] = 0xFF;
+               eui[4] = 0xFE;
+               eui[0] ^= 2;
+       }
+       return 0;
+}
+
+static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev)
+{
+       /* XXX: inherit EUI-64 from other interface -- yoshfuji */
+       if (dev->addr_len != ARCNET_ALEN)
+               return -1;
+       memset(eui, 0, 7);
+       eui[7] = *(u8*)dev->dev_addr;
+       return 0;
+}
+
+static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev)
+{
+       if (dev->addr_len != INFINIBAND_ALEN)
+               return -1;
+       memcpy(eui, dev->dev_addr + 12, 8);
+       eui[0] |= 2;
+       return 0;
+}
+
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
 {
        switch (dev->type) {
        case ARPHRD_ETHER:
        case ARPHRD_FDDI:
        case ARPHRD_IEEE802_TR:
-               if (dev->addr_len != ETH_ALEN)
-                       return -1;
-               memcpy(eui, dev->dev_addr, 3);
-               memcpy(eui + 5, dev->dev_addr + 3, 3);
-
-               /*
-                * The zSeries OSA network cards can be shared among various
-                * OS instances, but the OSA cards have only one MAC address.
-                * This leads to duplicate address conflicts in conjunction
-                * with IPv6 if more than one instance uses the same card.
-                * 
-                * The driver for these cards can deliver a unique 16-bit
-                * identifier for each instance sharing the same card.  It is
-                * placed instead of 0xFFFE in the interface identifier.  The
-                * "u" bit of the interface identifier is not inverted in this
-                * case.  Hence the resulting interface identifier has local
-                * scope according to RFC2373.
-                */
-               if (dev->dev_id) {
-                       eui[3] = (dev->dev_id >> 8) & 0xFF;
-                       eui[4] = dev->dev_id & 0xFF;
-               } else {
-                       eui[3] = 0xFF;
-                       eui[4] = 0xFE;
-                       eui[0] ^= 2;
-               }
-               return 0;
+               return addrconf_ifid_eui48(eui, dev);
        case ARPHRD_ARCNET:
-               /* XXX: inherit EUI-64 from other interface -- yoshfuji */
-               if (dev->addr_len != ARCNET_ALEN)
-                       return -1;
-               memset(eui, 0, 7);
-               eui[7] = *(u8*)dev->dev_addr;
-               return 0;
+               return addrconf_ifid_arcnet(eui, dev);
        case ARPHRD_INFINIBAND:
-               if (dev->addr_len != INFINIBAND_ALEN)
-                       return -1;
-               memcpy(eui, dev->dev_addr + 12, 8);
-               eui[0] |= 2;
-               return 0;
+               return addrconf_ifid_infiniband(eui, dev);
        }
        return -1;
 }
@@ -1376,34 +1401,9 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
 /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
 static int __ipv6_regen_rndid(struct inet6_dev *idev)
 {
-       struct net_device *dev;
-       struct scatterlist sg[2];
-
-       sg_set_buf(&sg[0], idev->entropy, 8);
-       sg_set_buf(&sg[1], idev->work_eui64, 8);
-
-       dev = idev->dev;
-
-       if (ipv6_generate_eui64(idev->work_eui64, dev)) {
-               printk(KERN_INFO
-                       "__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n",
-                       idev);
-               get_random_bytes(idev->work_eui64, sizeof(idev->work_eui64));
-       }
 regen:
-       spin_lock(&md5_tfm_lock);
-       if (unlikely(md5_tfm == NULL)) {
-               spin_unlock(&md5_tfm_lock);
-               return -1;
-       }
-       crypto_digest_init(md5_tfm);
-       crypto_digest_update(md5_tfm, sg, 2);
-       crypto_digest_final(md5_tfm, idev->work_digest);
-       spin_unlock(&md5_tfm_lock);
-
-       memcpy(idev->rndid, &idev->work_digest[0], 8);
+       get_random_bytes(idev->rndid, sizeof(idev->rndid));
        idev->rndid[0] &= ~0x02;
-       memcpy(idev->entropy, &idev->work_digest[8], 8);
 
        /*
         * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
@@ -2143,7 +2143,6 @@ static void addrconf_ip6_tnl_config(struct net_device *dev)
                return;
        }
        ip6_tnl_add_linklocal(idev);
-       addrconf_add_mroute(dev);
 }
 
 static int addrconf_notify(struct notifier_block *this, unsigned long event, 
@@ -2668,11 +2667,10 @@ static int if6_seq_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct if6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
 
        if (!s)
                goto out;
-       memset(s, 0, sizeof(*s));
 
        rc = seq_open(file, &if6_seq_ops);
        if (rc)
@@ -3133,6 +3131,15 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
 #endif
        array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
+       array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr;
+       array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
+#ifdef CONFIG_IPV6_ROUTER_PREF
+       array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
+       array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval;
+#ifdef CONFIV_IPV6_ROUTE_INFO
+       array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
+#endif
+#endif
 }
 
 static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 
@@ -3586,6 +3593,51 @@ static struct addrconf_sysctl_table
                        .proc_handler   =       &proc_dointvec,
                },
                {
+                       .ctl_name       =       NET_IPV6_ACCEPT_RA_DEFRTR,
+                       .procname       =       "accept_ra_defrtr",
+                       .data           =       &ipv6_devconf.accept_ra_defrtr,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
+               {
+                       .ctl_name       =       NET_IPV6_ACCEPT_RA_PINFO,
+                       .procname       =       "accept_ra_pinfo",
+                       .data           =       &ipv6_devconf.accept_ra_pinfo,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
+#ifdef CONFIG_IPV6_ROUTER_PREF
+               {
+                       .ctl_name       =       NET_IPV6_ACCEPT_RA_RTR_PREF,
+                       .procname       =       "accept_ra_rtr_pref",
+                       .data           =       &ipv6_devconf.accept_ra_rtr_pref,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
+               {
+                       .ctl_name       =       NET_IPV6_RTR_PROBE_INTERVAL,
+                       .procname       =       "router_probe_interval",
+                       .data           =       &ipv6_devconf.rtr_probe_interval,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec_jiffies,
+                       .strategy       =       &sysctl_jiffies,
+               },
+#ifdef CONFIV_IPV6_ROUTE_INFO
+               {
+                       .ctl_name       =       NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,
+                       .procname       =       "accept_ra_rt_info_max_plen",
+                       .data           =       &ipv6_devconf.accept_ra_rt_info_max_plen,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
+#endif
+#endif
+               {
                        .ctl_name       =       0,      /* sentinel */
                }
        },
@@ -3760,13 +3812,6 @@ int __init addrconf_init(void)
 
        register_netdevice_notifier(&ipv6_dev_notf);
 
-#ifdef CONFIG_IPV6_PRIVACY
-       md5_tfm = crypto_alloc_tfm("md5", 0);
-       if (unlikely(md5_tfm == NULL))
-               printk(KERN_WARNING
-                       "failed to load transform for md5\n");
-#endif
-
        addrconf_verify(0);
        rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
 #ifdef CONFIG_SYSCTL
@@ -3829,11 +3874,6 @@ void __exit addrconf_cleanup(void)
 
        rtnl_unlock();
 
-#ifdef CONFIG_IPV6_PRIVACY
-       crypto_free_tfm(md5_tfm);
-       md5_tfm = NULL;
-#endif
-
 #ifdef CONFIG_PROC_FS
        proc_net_remove("if_inet6");
 #endif
index 6c9711a..e19457f 100644 (file)
@@ -456,45 +456,53 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 }
 
 const struct proto_ops inet6_stream_ops = {
-       .family =       PF_INET6,
-       .owner =        THIS_MODULE,
-       .release =      inet6_release,
-       .bind =         inet6_bind,
-       .connect =      inet_stream_connect,            /* ok           */
-       .socketpair =   sock_no_socketpair,             /* a do nothing */
-       .accept =       inet_accept,                    /* ok           */
-       .getname =      inet6_getname, 
-       .poll =         tcp_poll,                       /* ok           */
-       .ioctl =        inet6_ioctl,                    /* must change  */
-       .listen =       inet_listen,                    /* ok           */
-       .shutdown =     inet_shutdown,                  /* ok           */
-       .setsockopt =   sock_common_setsockopt,         /* ok           */
-       .getsockopt =   sock_common_getsockopt,         /* ok           */
-       .sendmsg =      inet_sendmsg,                   /* ok           */
-       .recvmsg =      sock_common_recvmsg,            /* ok           */
-       .mmap =         sock_no_mmap,
-       .sendpage =     tcp_sendpage
+       .family            = PF_INET6,
+       .owner             = THIS_MODULE,
+       .release           = inet6_release,
+       .bind              = inet6_bind,
+       .connect           = inet_stream_connect,       /* ok           */
+       .socketpair        = sock_no_socketpair,        /* a do nothing */
+       .accept            = inet_accept,               /* ok           */
+       .getname           = inet6_getname,
+       .poll              = tcp_poll,                  /* ok           */
+       .ioctl             = inet6_ioctl,               /* must change  */
+       .listen            = inet_listen,               /* ok           */
+       .shutdown          = inet_shutdown,             /* ok           */
+       .setsockopt        = sock_common_setsockopt,    /* ok           */
+       .getsockopt        = sock_common_getsockopt,    /* ok           */
+       .sendmsg           = inet_sendmsg,              /* ok           */
+       .recvmsg           = sock_common_recvmsg,       /* ok           */
+       .mmap              = sock_no_mmap,
+       .sendpage          = tcp_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 const struct proto_ops inet6_dgram_ops = {
-       .family =       PF_INET6,
-       .owner =        THIS_MODULE,
-       .release =      inet6_release,
-       .bind =         inet6_bind,
-       .connect =      inet_dgram_connect,             /* ok           */
-       .socketpair =   sock_no_socketpair,             /* a do nothing */
-       .accept =       sock_no_accept,                 /* a do nothing */
-       .getname =      inet6_getname, 
-       .poll =         udp_poll,                       /* ok           */
-       .ioctl =        inet6_ioctl,                    /* must change  */
-       .listen =       sock_no_listen,                 /* ok           */
-       .shutdown =     inet_shutdown,                  /* ok           */
-       .setsockopt =   sock_common_setsockopt,         /* ok           */
-       .getsockopt =   sock_common_getsockopt,         /* ok           */
-       .sendmsg =      inet_sendmsg,                   /* ok           */
-       .recvmsg =      sock_common_recvmsg,            /* ok           */
-       .mmap =         sock_no_mmap,
-       .sendpage =     sock_no_sendpage,
+       .family            = PF_INET6,
+       .owner             = THIS_MODULE,
+       .release           = inet6_release,
+       .bind              = inet6_bind,
+       .connect           = inet_dgram_connect,        /* ok           */
+       .socketpair        = sock_no_socketpair,        /* a do nothing */
+       .accept            = sock_no_accept,            /* a do nothing */
+       .getname           = inet6_getname,
+       .poll              = udp_poll,                  /* ok           */
+       .ioctl             = inet6_ioctl,               /* must change  */
+       .listen            = sock_no_listen,            /* ok           */
+       .shutdown          = inet_shutdown,             /* ok           */
+       .setsockopt        = sock_common_setsockopt,    /* ok           */
+       .getsockopt        = sock_common_getsockopt,    /* ok           */
+       .sendmsg           = inet_sendmsg,              /* ok           */
+       .recvmsg           = sock_common_recvmsg,       /* ok           */
+       .mmap              = sock_no_mmap,
+       .sendpage          = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 static struct net_proto_family inet6_family_ops = {
@@ -505,24 +513,28 @@ static struct net_proto_family inet6_family_ops = {
 
 /* Same as inet6_dgram_ops, sans udp_poll.  */
 static const struct proto_ops inet6_sockraw_ops = {
-       .family =       PF_INET6,
-       .owner =        THIS_MODULE,
-       .release =      inet6_release,
-       .bind =         inet6_bind,
-       .connect =      inet_dgram_connect,             /* ok           */
-       .socketpair =   sock_no_socketpair,             /* a do nothing */
-       .accept =       sock_no_accept,                 /* a do nothing */
-       .getname =      inet6_getname, 
-       .poll =         datagram_poll,                  /* ok           */
-       .ioctl =        inet6_ioctl,                    /* must change  */
-       .listen =       sock_no_listen,                 /* ok           */
-       .shutdown =     inet_shutdown,                  /* ok           */
-       .setsockopt =   sock_common_setsockopt,         /* ok           */
-       .getsockopt =   sock_common_getsockopt,         /* ok           */
-       .sendmsg =      inet_sendmsg,                   /* ok           */
-       .recvmsg =      sock_common_recvmsg,            /* ok           */
-       .mmap =         sock_no_mmap,
-       .sendpage =     sock_no_sendpage,
+       .family            = PF_INET6,
+       .owner             = THIS_MODULE,
+       .release           = inet6_release,
+       .bind              = inet6_bind,
+       .connect           = inet_dgram_connect,        /* ok           */
+       .socketpair        = sock_no_socketpair,        /* a do nothing */
+       .accept            = sock_no_accept,            /* a do nothing */
+       .getname           = inet6_getname,
+       .poll              = datagram_poll,             /* ok           */
+       .ioctl             = inet6_ioctl,               /* must change  */
+       .listen            = sock_no_listen,            /* ok           */
+       .shutdown          = inet_shutdown,             /* ok           */
+       .setsockopt        = sock_common_setsockopt,    /* ok           */
+       .getsockopt        = sock_common_getsockopt,    /* ok           */
+       .sendmsg           = inet_sendmsg,              /* ok           */
+       .recvmsg           = sock_common_recvmsg,       /* ok           */
+       .mmap              = sock_no_mmap,
+       .sendpage          = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 static struct inet_protosw rawv6_protosw = {
index 8496374..cf58251 100644 (file)
@@ -213,6 +213,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
        ah->reserved = 0;
        ah->spi = x->id.spi;
        ah->seq_no = htonl(++x->replay.oseq);
+       xfrm_aevent_doreplay(x);
        ahp->icv(ahp, skb, ah->auth_data);
 
        err = 0;
@@ -353,12 +354,10 @@ static int ah6_init_state(struct xfrm_state *x)
        if (x->encap)
                goto error;
 
-       ahp = kmalloc(sizeof(*ahp), GFP_KERNEL);
+       ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
        if (ahp == NULL)
                return -ENOMEM;
 
-       memset(ahp, 0, sizeof(*ahp));
-
        ahp->key = x->aalg->alg_key;
        ahp->key_len = (x->aalg->alg_key_len+7)/8;
        ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
index 840a33d..39ec528 100644 (file)
@@ -308,7 +308,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
         *      not found: create a new one.
         */
 
-       aca = kmalloc(sizeof(struct ifacaddr6), GFP_ATOMIC);
+       aca = kzalloc(sizeof(struct ifacaddr6), GFP_ATOMIC);
 
        if (aca == NULL) {
                err = -ENOMEM;
@@ -322,8 +322,6 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
                goto out;
        }
 
-       memset(aca, 0, sizeof(struct ifacaddr6));
-
        ipv6_addr_copy(&aca->aca_addr, addr);
        aca->aca_idev = idev;
        aca->aca_rt = rt;
@@ -550,7 +548,7 @@ static int ac6_seq_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct ac6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct ac6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
 
        if (!s)
                goto out;
@@ -561,7 +559,6 @@ static int ac6_seq_open(struct inode *inode, struct file *file)
 
        seq = file->private_data;
        seq->private = s;
-       memset(s, 0, sizeof(*s));
 out:
        return rc;
 out_kfree:
index 7b5b94f..3dcaac7 100644 (file)
@@ -94,6 +94,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 
        esph->spi = x->id.spi;
        esph->seq_no = htonl(++x->replay.oseq);
+       xfrm_aevent_doreplay(x);
 
        if (esp->conf.ivlen)
                crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
@@ -304,12 +305,10 @@ static int esp6_init_state(struct xfrm_state *x)
        if (x->encap)
                goto error;
 
-       esp = kmalloc(sizeof(*esp), GFP_KERNEL);
+       esp = kzalloc(sizeof(*esp), GFP_KERNEL);
        if (esp == NULL)
                return -ENOMEM;
 
-       memset(esp, 0, sizeof(*esp));
-
        if (x->aalg) {
                struct xfrm_algo_desc *aalg_desc;
 
index 1bf6d9a..2cb6149 100644 (file)
@@ -1105,7 +1105,6 @@ static int fib6_age(struct rt6_info *rt, void *arg)
        if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) {
                if (time_after(now, rt->rt6i_expires)) {
                        RT6_TRACE("expiring %p\n", rt);
-                       rt6_reset_dflt_pointer(rt);
                        return -1;
                }
                gc_args.more++;
index 69cbe8a..f9ca639 100644 (file)
@@ -287,10 +287,9 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *
        int err;
 
        err = -ENOMEM;
-       fl = kmalloc(sizeof(*fl), GFP_KERNEL);
+       fl = kzalloc(sizeof(*fl), GFP_KERNEL);
        if (fl == NULL)
                goto done;
-       memset(fl, 0, sizeof(*fl));
 
        olen = optlen - CMSG_ALIGN(sizeof(*freq));
        if (olen > 0) {
@@ -663,7 +662,7 @@ static int ip6fl_seq_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct ip6fl_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct ip6fl_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
 
        if (!s)
                goto out;
@@ -674,7 +673,6 @@ static int ip6fl_seq_open(struct inode *inode, struct file *file)
 
        seq = file->private_data;
        seq->private = s;
-       memset(s, 0, sizeof(*s));
 out:
        return rc;
 out_kfree:
index 5bf70b1..4fbc40b 100644 (file)
@@ -733,28 +733,29 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
                if (*dst) {
                        struct rt6_info *rt = (struct rt6_info*)*dst;
        
-                               /* Yes, checking route validity in not connected
-                                  case is not very simple. Take into account,
-                                  that we do not support routing by source, TOS,
-                                  and MSG_DONTROUTE            --ANK (980726)
-       
-                                  1. If route was host route, check that
-                                     cached destination is current.
-                                     If it is network route, we still may
-                                     check its validity using saved pointer
-                                     to the last used address: daddr_cache.
-                                     We do not want to save whole address now,
-                                     (because main consumer of this service
-                                      is tcp, which has not this problem),
-                                     so that the last trick works only on connected
-                                     sockets.
-                                  2. oif also should be the same.
-                                */
-       
+                       /* Yes, checking route validity in not connected
+                        * case is not very simple. Take into account,
+                        * that we do not support routing by source, TOS,
+                        * and MSG_DONTROUTE            --ANK (980726)
+                        *
+                        * 1. If route was host route, check that
+                        *    cached destination is current.
+                        *    If it is network route, we still may
+                        *    check its validity using saved pointer
+                        *    to the last used address: daddr_cache.
+                        *    We do not want to save whole address now,
+                        *    (because main consumer of this service
+                        *    is tcp, which has not this problem),
+                        *    so that the last trick works only on connected
+                        *    sockets.
+                        * 2. oif also should be the same.
+                        */
                        if (((rt->rt6i_dst.plen != 128 ||
-                             !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr))
+                             !ipv6_addr_equal(&fl->fl6_dst,
+                                              &rt->rt6i_dst.addr))
                             && (np->daddr_cache == NULL ||
-                                !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache)))
+                                !ipv6_addr_equal(&fl->fl6_dst,
+                                                 np->daddr_cache)))
                            || (fl->oif && fl->oif != (*dst)->dev->ifindex)) {
                                dst_release(*dst);
                                *dst = NULL;
@@ -889,7 +890,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
                np->cork.hop_limit = hlimit;
                np->cork.tclass = tclass;
                mtu = dst_mtu(rt->u.dst.path);
-               if (np && np->frag_size < mtu) {
+               if (np->frag_size < mtu) {
                        if (np->frag_size)
                                mtu = np->frag_size;
                }
index d511a88..028b636 100644 (file)
@@ -50,6 +50,7 @@
 #include <net/protocol.h>
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
+#include <linux/mutex.h>
 
 struct ipcomp6_tfms {
        struct list_head list;
@@ -57,7 +58,7 @@ struct ipcomp6_tfms {
        int users;
 };
 
-static DECLARE_MUTEX(ipcomp6_resource_sem);
+static DEFINE_MUTEX(ipcomp6_resource_mutex);
 static void **ipcomp6_scratches;
 static int ipcomp6_scratch_users;
 static LIST_HEAD(ipcomp6_tfms_list);
@@ -286,8 +287,8 @@ static void ipcomp6_free_scratches(void)
 
        for_each_cpu(i) {
                void *scratch = *per_cpu_ptr(scratches, i);
-               if (scratch)
-                       vfree(scratch);
+
+               vfree(scratch);
        }
 
        free_percpu(scratches);
@@ -405,9 +406,9 @@ static void ipcomp6_destroy(struct xfrm_state *x)
        if (!ipcd)
                return;
        xfrm_state_delete_tunnel(x);
-       down(&ipcomp6_resource_sem);
+       mutex_lock(&ipcomp6_resource_mutex);
        ipcomp6_free_data(ipcd);
-       up(&ipcomp6_resource_sem);
+       mutex_unlock(&ipcomp6_resource_mutex);
        kfree(ipcd);
 
        xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
@@ -427,23 +428,22 @@ static int ipcomp6_init_state(struct xfrm_state *x)
                goto out;
 
        err = -ENOMEM;
-       ipcd = kmalloc(sizeof(*ipcd), GFP_KERNEL);
+       ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL);
        if (!ipcd)
                goto out;
 
-       memset(ipcd, 0, sizeof(*ipcd));
        x->props.header_len = 0;
        if (x->props.mode)
                x->props.header_len += sizeof(struct ipv6hdr);
        
-       down(&ipcomp6_resource_sem);
+       mutex_lock(&ipcomp6_resource_mutex);
        if (!ipcomp6_alloc_scratches())
                goto error;
 
        ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name);
        if (!ipcd->tfms)
                goto error;
-       up(&ipcomp6_resource_sem);
+       mutex_unlock(&ipcomp6_resource_mutex);
 
        if (x->props.mode) {
                err = ipcomp6_tunnel_attach(x);
@@ -459,10 +459,10 @@ static int ipcomp6_init_state(struct xfrm_state *x)
 out:
        return err;
 error_tunnel:
-       down(&ipcomp6_resource_sem);
+       mutex_lock(&ipcomp6_resource_mutex);
 error:
        ipcomp6_free_data(ipcd);
-       up(&ipcomp6_resource_sem);
+       mutex_unlock(&ipcomp6_resource_mutex);
        kfree(ipcd);
 
        goto out;
index f7142ba..602feec 100644 (file)
@@ -109,19 +109,13 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
        return 0;
 }
 
-int ipv6_setsockopt(struct sock *sk, int level, int optname,
+static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int optlen)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        int val, valbool;
        int retv = -ENOPROTOOPT;
 
-       if (level == SOL_IP && sk->sk_type != SOCK_RAW)
-               return udp_prot.setsockopt(sk, level, optname, optval, optlen);
-
-       if(level!=SOL_IPV6)
-               goto out;
-
        if (optval == NULL)
                val=0;
        else if (get_user(val, (int __user *) optval))
@@ -613,17 +607,9 @@ done:
                retv = xfrm_user_policy(sk, optname, optval, optlen);
                break;
 
-#ifdef CONFIG_NETFILTER
-       default:
-               retv = nf_setsockopt(sk, PF_INET6, optname, optval, 
-                                           optlen);
-               break;
-#endif
-
        }
        release_sock(sk);
 
-out:
        return retv;
 
 e_inval:
@@ -631,6 +617,65 @@ e_inval:
        return -EINVAL;
 }
 
+int ipv6_setsockopt(struct sock *sk, int level, int optname,
+                   char __user *optval, int optlen)
+{
+       int err;
+
+       if (level == SOL_IP && sk->sk_type != SOCK_RAW)
+               return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+
+       if (level != SOL_IPV6)
+               return -ENOPROTOOPT;
+
+       err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
+                       optname != IPV6_XFRM_POLICY) {
+               lock_sock(sk);
+               err = nf_setsockopt(sk, PF_INET6, optname, optval,
+                               optlen);
+               release_sock(sk);
+       }
+#endif
+       return err;
+}
+
+
+#ifdef CONFIG_COMPAT
+int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
+                          char __user *optval, int optlen)
+{
+       int err;
+
+       if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
+               if (udp_prot.compat_setsockopt != NULL)
+                       return udp_prot.compat_setsockopt(sk, level, optname,
+                                                         optval, optlen);
+               return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+       }
+
+       if (level != SOL_IPV6)
+               return -ENOPROTOOPT;
+
+       err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
+           optname != IPV6_XFRM_POLICY) {
+               lock_sock(sk);
+               err = compat_nf_setsockopt(sk, PF_INET6, optname,
+                                          optval, optlen);
+               release_sock(sk);
+       }
+#endif
+       return err;
+}
+
+EXPORT_SYMBOL(compat_ipv6_setsockopt);
+#endif
+
 static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr,
                                  char __user *optval, int len)
 {
@@ -642,17 +687,13 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr,
        return len;
 }
 
-int ipv6_getsockopt(struct sock *sk, int level, int optname,
+static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int __user *optlen)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        int len;
        int val;
 
-       if (level == SOL_IP && sk->sk_type != SOCK_RAW)
-               return udp_prot.getsockopt(sk, level, optname, optval, optlen);
-       if(level!=SOL_IPV6)
-               return -ENOPROTOOPT;
        if (get_user(len, optlen))
                return -EFAULT;
        switch (optname) {
@@ -842,17 +883,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
                break;
 
        default:
-#ifdef CONFIG_NETFILTER
-               lock_sock(sk);
-               val = nf_getsockopt(sk, PF_INET6, optname, optval, 
-                                   &len);
-               release_sock(sk);
-               if (val >= 0)
-                       val = put_user(len, optlen);
-               return val;
-#else
                return -EINVAL;
-#endif
        }
        len = min_t(unsigned int, sizeof(int), len);
        if(put_user(len, optlen))
@@ -862,6 +893,78 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
        return 0;
 }
 
+int ipv6_getsockopt(struct sock *sk, int level, int optname,
+                   char __user *optval, int __user *optlen)
+{
+       int err;
+
+       if (level == SOL_IP && sk->sk_type != SOCK_RAW)
+               return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+
+       if(level != SOL_IPV6)
+               return -ENOPROTOOPT;
+
+       err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible EINVALs except default case */
+       if (err == -ENOPROTOOPT && optname != IPV6_ADDRFORM &&
+                       optname != MCAST_MSFILTER) {
+               int len;
+
+               if (get_user(len, optlen))
+                       return -EFAULT;
+
+               lock_sock(sk);
+               err = nf_getsockopt(sk, PF_INET6, optname, optval,
+                               &len);
+               release_sock(sk);
+               if (err >= 0)
+                       err = put_user(len, optlen);
+       }
+#endif
+       return err;
+}
+
+#ifdef CONFIG_COMPAT
+int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
+                          char __user *optval, int __user *optlen)
+{
+       int err;
+
+       if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
+               if (udp_prot.compat_getsockopt != NULL)
+                       return udp_prot.compat_getsockopt(sk, level, optname,
+                                                         optval, optlen);
+               return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+       }
+
+       if (level != SOL_IPV6)
+               return -ENOPROTOOPT;
+
+       err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible EINVALs except default case */
+       if (err == -ENOPROTOOPT && optname != IPV6_ADDRFORM &&
+                       optname != MCAST_MSFILTER) {
+               int len;
+
+               if (get_user(len, optlen))
+                       return -EFAULT;
+
+               lock_sock(sk);
+               err = compat_nf_getsockopt(sk, PF_INET6,
+                                          optname, optval, &len);
+               release_sock(sk);
+               if (err >= 0)
+                       err = put_user(len, optlen);
+       }
+#endif
+       return err;
+}
+
+EXPORT_SYMBOL(compat_ipv6_getsockopt);
+#endif
+
 void __init ipv6_packet_init(void)
 {
        dev_add_pack(&ipv6_packet_type);
index 807c021..6e871af 100644 (file)
@@ -767,10 +767,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
         * for deleted items allows change reports to use common code with
         * non-deleted or query-response MCA's.
         */
-       pmc = kmalloc(sizeof(*pmc), GFP_ATOMIC);
+       pmc = kzalloc(sizeof(*pmc), GFP_ATOMIC);
        if (!pmc)
                return;
-       memset(pmc, 0, sizeof(*pmc));
+
        spin_lock_bh(&im->mca_lock);
        spin_lock_init(&pmc->mca_lock);
        pmc->idev = im->idev;
@@ -893,7 +893,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
         *      not found: create a new one.
         */
 
-       mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
+       mc = kzalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
 
        if (mc == NULL) {
                write_unlock_bh(&idev->lock);
@@ -901,7 +901,6 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
                return -ENOMEM;
        }
 
-       memset(mc, 0, sizeof(struct ifmcaddr6));
        init_timer(&mc->mca_timer);
        mc->mca_timer.function = igmp6_timer_handler;
        mc->mca_timer.data = (unsigned long) mc;
@@ -1934,10 +1933,10 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
                psf_prev = psf;
        }
        if (!psf) {
-               psf = kmalloc(sizeof(*psf), GFP_ATOMIC);
+               psf = kzalloc(sizeof(*psf), GFP_ATOMIC);
                if (!psf)
                        return -ENOBUFS;
-               memset(psf, 0, sizeof(*psf));
+
                psf->sf_addr = *psfsrc;
                if (psf_prev) {
                        psf_prev->sf_next = psf;
@@ -2431,7 +2430,7 @@ static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct igmp6_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct igmp6_mc_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
 
        if (!s)
                goto out;
@@ -2442,7 +2441,6 @@ static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
 
        seq = file->private_data;
        seq->private = s;
-       memset(s, 0, sizeof(*s));
 out:
        return rc;
 out_kfree:
@@ -2606,7 +2604,7 @@ static int igmp6_mcf_seq_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct igmp6_mcf_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct igmp6_mcf_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
        
        if (!s)
                goto out;
@@ -2617,7 +2615,6 @@ static int igmp6_mcf_seq_open(struct inode *inode, struct file *file)
 
        seq = file->private_data;
        seq->private = s;
-       memset(s, 0, sizeof(*s));
 out:
        return rc;
 out_kfree:
index cb8856b..dfa20d3 100644 (file)
@@ -156,7 +156,11 @@ struct neigh_table nd_tbl = {
 
 /* ND options */
 struct ndisc_options {
-       struct nd_opt_hdr *nd_opt_array[__ND_OPT_MAX];
+       struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
+#ifdef CONFIG_IPV6_ROUTE_INFO
+       struct nd_opt_hdr *nd_opts_ri;
+       struct nd_opt_hdr *nd_opts_ri_end;
+#endif
 };
 
 #define nd_opts_src_lladdr     nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
@@ -255,6 +259,13 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
                        if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
                                ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
                        break;
+#ifdef CONFIG_IPV6_ROUTE_INFO
+               case ND_OPT_ROUTE_INFO:
+                       ndopts->nd_opts_ri_end = nd_opt;
+                       if (!ndopts->nd_opts_ri)
+                               ndopts->nd_opts_ri = nd_opt;
+                       break;
+#endif
                default:
                        /*
                         * Unknown options must be silently ignored,
@@ -1019,10 +1030,11 @@ static void ndisc_router_discovery(struct sk_buff *skb)
         struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
        struct neighbour *neigh = NULL;
        struct inet6_dev *in6_dev;
-       struct rt6_info *rt;
+       struct rt6_info *rt = NULL;
        int lifetime;
        struct ndisc_options ndopts;
        int optlen;
+       unsigned int pref = 0;
 
        __u8 * opt = (__u8 *)(ra_msg + 1);
 
@@ -1081,8 +1093,19 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                                (ra_msg->icmph.icmp6_addrconf_other ?
                                        IF_RA_OTHERCONF : 0);
 
+       if (!in6_dev->cnf.accept_ra_defrtr)
+               goto skip_defrtr;
+
        lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
 
+#ifdef CONFIG_IPV6_ROUTER_PREF
+       pref = ra_msg->icmph.icmp6_router_pref;
+       /* 10b is handled as if it were 00b (medium) */
+       if (pref == ICMPV6_ROUTER_PREF_INVALID ||
+           in6_dev->cnf.accept_ra_rtr_pref)
+               pref = ICMPV6_ROUTER_PREF_MEDIUM;
+#endif
+
        rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
 
        if (rt)
@@ -1098,7 +1121,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                ND_PRINTK3(KERN_DEBUG
                           "ICMPv6 RA: adding default router.\n");
 
-               rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+               rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
                if (rt == NULL) {
                        ND_PRINTK0(KERN_ERR
                                   "ICMPv6 RA: %s() failed to add default route.\n",
@@ -1117,6 +1140,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                        return;
                }
                neigh->flags |= NTF_ROUTER;
+       } else if (rt) {
+               rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
        }
 
        if (rt)
@@ -1128,6 +1153,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                        rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
        }
 
+skip_defrtr:
+
        /*
         *      Update Reachable Time and Retrans Timer
         */
@@ -1186,7 +1213,21 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                             NEIGH_UPDATE_F_ISROUTER);
        }
 
-       if (ndopts.nd_opts_pi) {
+#ifdef CONFIG_IPV6_ROUTE_INFO
+       if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
+               struct nd_opt_hdr *p;
+               for (p = ndopts.nd_opts_ri;
+                    p;
+                    p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
+                       if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
+                               continue;
+                       rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
+                                     &skb->nh.ipv6h->saddr);
+               }
+       }
+#endif
+
+       if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
                struct nd_opt_hdr *p;
                for (p = ndopts.nd_opts_pi;
                     p;
index 2d6f8ec..98f7875 100644 (file)
@@ -133,16 +133,6 @@ config IP6_NF_MATCH_EUI64
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_POLICY
-       tristate "IPsec policy match support"
-       depends on IP6_NF_IPTABLES && XFRM
-       help
-         Policy matching allows you to match packets based on the
-         IPsec policy that was used during decapsulation/will
-         be used during encapsulation.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 # The targets
 config IP6_NF_FILTER
        tristate "Packet filtering"
index db6073c..8436a1a 100644 (file)
@@ -9,7 +9,6 @@ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
 obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
 obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
-obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
index af06350..344eab3 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/spinlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
@@ -65,7 +66,7 @@ static unsigned int queue_dropped = 0;
 static unsigned int queue_user_dropped = 0;
 static struct sock *ipqnl;
 static LIST_HEAD(queue_list);
-static DECLARE_MUTEX(ipqnl_sem);
+static DEFINE_MUTEX(ipqnl_mutex);
 
 static void
 ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
@@ -537,7 +538,7 @@ ipq_rcv_sk(struct sock *sk, int len)
        struct sk_buff *skb;
        unsigned int qlen;
 
-       down(&ipqnl_sem);
+       mutex_lock(&ipqnl_mutex);
                        
        for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
                skb = skb_dequeue(&sk->sk_receive_queue);
@@ -545,7 +546,7 @@ ipq_rcv_sk(struct sock *sk, int len)
                kfree_skb(skb);
        }
                
-       up(&ipqnl_sem);
+       mutex_unlock(&ipqnl_mutex);
 }
 
 static int
@@ -704,8 +705,8 @@ cleanup_sysctl:
        
 cleanup_ipqnl:
        sock_release(ipqnl->sk_socket);
-       down(&ipqnl_sem);
-       up(&ipqnl_sem);
+       mutex_lock(&ipqnl_mutex);
+       mutex_unlock(&ipqnl_mutex);
        
 cleanup_netlink_notifier:
        netlink_unregister_notifier(&ipq_nl_notifier);
index 74ff56c..5a2063b 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/icmpv6.h>
 #include <net/ipv6.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/proc_fs.h>
 #include <linux/cpumask.h>
 
@@ -94,19 +94,6 @@ do {                                                         \
 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
 #endif
 
-int
-ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask,
-                   const struct in6_addr *addr2)
-{
-       int i;
-       for( i = 0; i < 16; i++){
-               if((addr1->s6_addr[i] & mask->s6_addr[i]) != 
-                  (addr2->s6_addr[i] & mask->s6_addr[i]))
-                       return 1;
-       }
-       return 0;
-}
-
 /* Check for an extension */
 int 
 ip6t_ext_hdr(u8 nexthdr)
@@ -135,10 +122,10 @@ ip6_packet_match(const struct sk_buff *skb,
 
 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
 
-       if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk,
-                                    &ip6info->src), IP6T_INV_SRCIP)
-           || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk,
-                                       &ip6info->dst), IP6T_INV_DSTIP)) {
+       if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
+                                      &ip6info->src), IP6T_INV_SRCIP)
+           || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
+                                         &ip6info->dst), IP6T_INV_DSTIP)) {
                dprintf("Source or dest mismatch.\n");
 /*
                dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
@@ -232,6 +219,7 @@ ip6t_error(struct sk_buff **pskb,
          const struct net_device *in,
          const struct net_device *out,
          unsigned int hooknum,
+         const struct xt_target *target,
          const void *targinfo,
          void *userinfo)
 {
@@ -251,7 +239,7 @@ int do_match(struct ip6t_entry_match *m,
             int *hotdrop)
 {
        /* Stop iteration if it doesn't match */
-       if (!m->u.kernel.match->match(skb, in, out, m->data,
+       if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
                                      offset, protoff, hotdrop))
                return 1;
        else
@@ -373,6 +361,7 @@ ip6t_do_table(struct sk_buff **pskb,
                                verdict = t->u.kernel.target->target(pskb,
                                                                     in, out,
                                                                     hook,
+                                                                    t->u.kernel.target,
                                                                     t->data,
                                                                     userdata);
 
@@ -531,7 +520,7 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
                return 1;
 
        if (m->u.kernel.match->destroy)
-               m->u.kernel.match->destroy(m->data,
+               m->u.kernel.match->destroy(m->u.kernel.match, m->data,
                                           m->u.match_size - sizeof(*m));
        module_put(m->u.kernel.match->me);
        return 0;
@@ -544,21 +533,12 @@ standard_check(const struct ip6t_entry_target *t,
        struct ip6t_standard_target *targ = (void *)t;
 
        /* Check standard info. */
-       if (t->u.target_size
-           != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
-               duprintf("standard_check: target size %u != %u\n",
-                        t->u.target_size,
-                        IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
-               return 0;
-       }
-
        if (targ->verdict >= 0
            && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
                duprintf("ip6t_standard_check: bad verdict (%i)\n",
                         targ->verdict);
                return 0;
        }
-
        if (targ->verdict < -NF_MAX_VERDICT - 1) {
                duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
                         targ->verdict);
@@ -575,6 +555,7 @@ check_match(struct ip6t_entry_match *m,
            unsigned int *i)
 {
        struct ip6t_match *match;
+       int ret;
 
        match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
                                        m->u.user.revision),
@@ -585,18 +566,27 @@ check_match(struct ip6t_entry_match *m,
        }
        m->u.kernel.match = match;
 
+       ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
+                            name, hookmask, ipv6->proto,
+                            ipv6->invflags & IP6T_INV_PROTO);
+       if (ret)
+               goto err;
+
        if (m->u.kernel.match->checkentry
-           && !m->u.kernel.match->checkentry(name, ipv6, m->data,
+           && !m->u.kernel.match->checkentry(name, ipv6, match,  m->data,
                                              m->u.match_size - sizeof(*m),
                                              hookmask)) {
-               module_put(m->u.kernel.match->me);
                duprintf("ip_tables: check failed for `%s'.\n",
                         m->u.kernel.match->name);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
 
        (*i)++;
        return 0;
+err:
+       module_put(m->u.kernel.match->me);
+       return ret;
 }
 
 static struct ip6t_target ip6t_standard_target;
@@ -632,26 +622,32 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
        }
        t->u.kernel.target = target;
 
+       ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
+                             name, e->comefrom, e->ipv6.proto,
+                             e->ipv6.invflags & IP6T_INV_PROTO);
+       if (ret)
+               goto err;
+
        if (t->u.kernel.target == &ip6t_standard_target) {
                if (!standard_check(t, size)) {
                        ret = -EINVAL;
                        goto cleanup_matches;
                }
        } else if (t->u.kernel.target->checkentry
-                  && !t->u.kernel.target->checkentry(name, e, t->data,
+                  && !t->u.kernel.target->checkentry(name, e, target, t->data,
                                                      t->u.target_size
                                                      - sizeof(*t),
                                                      e->comefrom)) {
-               module_put(t->u.kernel.target->me);
                duprintf("ip_tables: check failed for `%s'.\n",
                         t->u.kernel.target->name);
                ret = -EINVAL;
-               goto cleanup_matches;
+               goto err;
        }
 
        (*i)++;
        return 0;
-
+ err:
+       module_put(t->u.kernel.target->me);
  cleanup_matches:
        IP6T_MATCH_ITERATE(e, cleanup_match, &j);
        return ret;
@@ -712,7 +708,7 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i)
        IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
        t = ip6t_get_target(e);
        if (t->u.kernel.target->destroy)
-               t->u.kernel.target->destroy(t->data,
+               t->u.kernel.target->destroy(t->u.kernel.target, t->data,
                                            t->u.target_size - sizeof(*t));
        module_put(t->u.kernel.target->me);
        return 0;
@@ -1333,6 +1329,7 @@ static int
 icmp6_match(const struct sk_buff *skb,
           const struct net_device *in,
           const struct net_device *out,
+          const struct xt_match *match,
           const void *matchinfo,
           int offset,
           unsigned int protoff,
@@ -1365,28 +1362,27 @@ icmp6_match(const struct sk_buff *skb,
 static int
 icmp6_checkentry(const char *tablename,
           const void *entry,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
-       const struct ip6t_ip6 *ipv6 = entry;
        const struct ip6t_icmp *icmpinfo = matchinfo;
 
-       /* Must specify proto == ICMP, and no unknown invflags */
-       return ipv6->proto == IPPROTO_ICMPV6
-               && !(ipv6->invflags & IP6T_INV_PROTO)
-               && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
-               && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
+       /* Must specify no unknown invflags */
+       return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
 }
 
 /* The built-in targets: standard (NULL) and error. */
 static struct ip6t_target ip6t_standard_target = {
        .name           = IP6T_STANDARD_TARGET,
+       .targetsize     = sizeof(int),
 };
 
 static struct ip6t_target ip6t_error_target = {
        .name           = IP6T_ERROR_TARGET,
        .target         = ip6t_error,
+       .targetsize     = IP6T_FUNCTION_MAXNAMELEN,
 };
 
 static struct nf_sockopt_ops ip6t_sockopts = {
@@ -1402,7 +1398,9 @@ static struct nf_sockopt_ops ip6t_sockopts = {
 static struct ip6t_match icmp6_matchstruct = {
        .name           = "icmp6",
        .match          = &icmp6_match,
-       .checkentry     = &icmp6_checkentry,
+       .matchsize      = sizeof(struct ip6t_icmp),
+       .checkentry     = icmp6_checkentry,
+       .proto          = IPPROTO_ICMPV6,
 };
 
 static int __init init(void)
@@ -1515,7 +1513,6 @@ EXPORT_SYMBOL(ip6t_unregister_table);
 EXPORT_SYMBOL(ip6t_do_table);
 EXPORT_SYMBOL(ip6t_ext_hdr);
 EXPORT_SYMBOL(ipv6_find_hdr);
-EXPORT_SYMBOL(ip6_masked_addrcmp);
 
 module_init(init);
 module_exit(fini);
index 306200c..da14c6d 100644 (file)
@@ -21,6 +21,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
                                   const struct net_device *in,
                                   const struct net_device *out,
                                   unsigned int hooknum,
+                                  const struct xt_target *target,
                                   const void *targinfo, void *userinfo)
 {
        struct ipv6hdr *ip6h;
@@ -63,43 +64,31 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
 
 static int ip6t_hl_checkentry(const char *tablename,
                const void *entry,
+               const struct xt_target *target,
                void *targinfo,
                unsigned int targinfosize,
                unsigned int hook_mask)
 {
        struct ip6t_HL_info *info = targinfo;
 
-       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
-               printk(KERN_WARNING "ip6t_HL: targinfosize %u != %Zu\n",
-                               targinfosize,
-                               IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
-               return 0;       
-       }       
-
-       if (strcmp(tablename, "mangle")) {
-               printk(KERN_WARNING "ip6t_HL: can only be called from "
-                       "\"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
        if (info->mode > IP6T_HL_MAXMODE) {
                printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", 
                        info->mode);
                return 0;
        }
-
        if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
                printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
                        "make sense with value 0\n");
                return 0;
        }
-       
        return 1;
 }
 
 static struct ip6t_target ip6t_HL = { 
        .name           = "HL", 
        .target         = ip6t_hl_target, 
+       .targetsize     = sizeof(struct ip6t_HL_info),
+       .table          = "mangle",
        .checkentry     = ip6t_hl_checkentry, 
        .me             = THIS_MODULE
 };
index 6b930ef..07c6bcb 100644 (file)
@@ -426,6 +426,7 @@ ip6t_log_target(struct sk_buff **pskb,
                const struct net_device *in,
                const struct net_device *out,
                unsigned int hooknum,
+               const struct xt_target *target,
                const void *targinfo,
                void *userinfo)
 {
@@ -449,35 +450,29 @@ ip6t_log_target(struct sk_buff **pskb,
 
 static int ip6t_log_checkentry(const char *tablename,
                               const void *entry,
+                              const struct xt_target *target,
                               void *targinfo,
                               unsigned int targinfosize,
                               unsigned int hook_mask)
 {
        const struct ip6t_log_info *loginfo = targinfo;
 
-       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_log_info))) {
-               DEBUGP("LOG: targinfosize %u != %u\n",
-                      targinfosize, IP6T_ALIGN(sizeof(struct ip6t_log_info)));
-               return 0;
-       }
-
        if (loginfo->level >= 8) {
                DEBUGP("LOG: level %u >= 8\n", loginfo->level);
                return 0;
        }
-
        if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
                DEBUGP("LOG: prefix term %i\n",
                       loginfo->prefix[sizeof(loginfo->prefix)-1]);
                return 0;
        }
-
        return 1;
 }
 
 static struct ip6t_target ip6t_log_reg = {
        .name           = "LOG",
        .target         = ip6t_log_target, 
+       .targetsize     = sizeof(struct ip6t_log_info),
        .checkentry     = ip6t_log_checkentry, 
        .me             = THIS_MODULE,
 };
index 0e6d1d4..ddfa385 100644 (file)
@@ -179,6 +179,7 @@ static unsigned int reject6_target(struct sk_buff **pskb,
                           const struct net_device *in,
                           const struct net_device *out,
                           unsigned int hooknum,
+                          const struct xt_target *target,
                           const void *targinfo,
                           void *userinfo)
 {
@@ -221,6 +222,7 @@ static unsigned int reject6_target(struct sk_buff **pskb,
 
 static int check(const char *tablename,
                 const void *entry,
+                const struct xt_target *target,
                 void *targinfo,
                 unsigned int targinfosize,
                 unsigned int hook_mask)
@@ -228,24 +230,6 @@ static int check(const char *tablename,
        const struct ip6t_reject_info *rejinfo = targinfo;
        const struct ip6t_entry *e = entry;
 
-       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
-               DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
-               return 0;
-       }
-
-       /* Only allow these for packet filtering. */
-       if (strcmp(tablename, "filter") != 0) {
-               DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
-               return 0;
-       }
-
-       if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
-                          | (1 << NF_IP6_FORWARD)
-                          | (1 << NF_IP6_LOCAL_OUT))) != 0) {
-               DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
-               return 0;
-       }
-
        if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
                printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
                return 0;
@@ -257,13 +241,16 @@ static int check(const char *tablename,
                        return 0;
                }
        }
-
        return 1;
 }
 
 static struct ip6t_target ip6t_reject_reg = {
        .name           = "REJECT",
        .target         = reject6_target,
+       .targetsize     = sizeof(struct ip6t_reject_info),
+       .table          = "filter",
+       .hooks          = (1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) |
+                         (1 << NF_IP6_LOCAL_OUT),
        .checkentry     = check,
        .me             = THIS_MODULE
 };
index 219a303..178f6fb 100644 (file)
@@ -44,6 +44,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -99,17 +100,13 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *entry,
+         const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ip6t_ah *ahinfo = matchinfo;
 
-       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
-               DEBUGP("ip6t_ah: matchsize %u != %u\n",
-                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
-               return 0;
-       }
        if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
                DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
                return 0;
@@ -119,8 +116,9 @@ checkentry(const char *tablename,
 
 static struct ip6t_match ah_match = {
        .name           = "ah",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_ah),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index b4c153a..e97a702 100644 (file)
@@ -55,6 +55,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -179,22 +180,17 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *info,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ip6t_opts *optsinfo = matchinfo;
 
-       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
-               DEBUGP("ip6t_opts: matchsize %u != %u\n",
-                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
-               return 0;
-       }
        if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
                DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
                return 0;
        }
-
        return 1;
 }
 
@@ -204,8 +200,9 @@ static struct ip6t_match opts_match = {
 #else
        .name           = "dst",
 #endif
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_opts),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 724285d..540b8bf 100644 (file)
@@ -44,6 +44,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -77,17 +78,13 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *ip,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ip6t_esp *espinfo = matchinfo;
 
-       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) {
-               DEBUGP("ip6t_esp: matchsize %u != %u\n",
-                        matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp)));
-               return 0;
-       }
        if (espinfo->invflags & ~IP6T_ESP_INV_MASK) {
                DEBUGP("ip6t_esp: unknown flags %X\n",
                         espinfo->invflags);
@@ -98,8 +95,9 @@ checkentry(const char *tablename,
 
 static struct ip6t_match esp_match = {
        .name           = "esp",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_esp),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 27396ac..d4b0bad 100644 (file)
@@ -22,6 +22,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -60,30 +61,12 @@ match(const struct sk_buff *skb,
        return 0;
 }
 
-static int
-ip6t_eui64_checkentry(const char *tablename,
-                     const void *ip,
-                     void *matchinfo,
-                     unsigned int matchsize,
-                     unsigned int hook_mask)
-{
-       if (hook_mask
-           & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
-               (1 << NF_IP6_FORWARD))) {
-               printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
-               return 0;
-       }
-
-       if (matchsize != IP6T_ALIGN(sizeof(int)))
-               return 0;
-
-       return 1;
-}
-
 static struct ip6t_match eui64_match = {
        .name           = "eui64",
-       .match          = &match,
-       .checkentry     = &ip6t_eui64_checkentry,
+       .match          = match,
+       .matchsize      = sizeof(int),
+       .hooks          = (1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
+                         (1 << NF_IP6_FORWARD),
        .me             = THIS_MODULE,
 };
 
index 4c14125..4c41e14 100644 (file)
@@ -43,6 +43,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -116,29 +117,25 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *ip,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ip6t_frag *fraginfo = matchinfo;
 
-       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) {
-               DEBUGP("ip6t_frag: matchsize %u != %u\n",
-                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag)));
-               return 0;
-       }
        if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
                DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags);
                return 0;
        }
-
        return 1;
 }
 
 static struct ip6t_match frag_match = {
        .name           = "frag",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_frag),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 37a8474..b4a1fdf 100644 (file)
@@ -55,6 +55,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -179,22 +180,17 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *entry,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ip6t_opts *optsinfo = matchinfo;
 
-       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
-               DEBUGP("ip6t_opts: matchsize %u != %u\n",
-                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
-               return 0;
-       }
        if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
                DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
                return 0;
        }
-
        return 1;
 }
 
@@ -204,8 +200,9 @@ static struct ip6t_match opts_match = {
 #else
        .name           = "dst",
 #endif
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_opts),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index c5d9079..3740557 100644 (file)
@@ -18,10 +18,10 @@ MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
 MODULE_DESCRIPTION("IP tables Hop Limit matching module");
 MODULE_LICENSE("GPL");
 
-static int match(const struct sk_buff *skb, const struct net_device *in,
-                const struct net_device *out, const void *matchinfo,
-                int offset, unsigned int protoff,
-                int *hotdrop)
+static int match(const struct sk_buff *skb,
+                const struct net_device *in, const struct net_device *out,
+                const struct xt_match *match, const void *matchinfo,
+                int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ip6t_hl_info *info = matchinfo;
        const struct ipv6hdr *ip6h = skb->nh.ipv6h;
@@ -48,20 +48,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return 0;
 }
 
-static int checkentry(const char *tablename, const void *entry,
-                     void *matchinfo, unsigned int matchsize,
-                     unsigned int hook_mask)
-{
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct ip6t_match hl_match = {
        .name           = "hl",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_hl_info),
        .me             = THIS_MODULE,
 };
 
index 83ad6b2..9375eeb 100644 (file)
@@ -29,6 +29,7 @@ static int
 ipv6header_match(const struct sk_buff *skb,
                 const struct net_device *in,
                 const struct net_device *out,
+                const struct xt_match *match,
                 const void *matchinfo,
                 int offset,
                 unsigned int protoff,
@@ -125,17 +126,13 @@ ipv6header_match(const struct sk_buff *skb,
 static int
 ipv6header_checkentry(const char *tablename,
                      const void *ip,
+                     const struct xt_match *match,
                      void *matchinfo,
                      unsigned int matchsize,
                      unsigned int hook_mask)
 {
        const struct ip6t_ipv6header_info *info = matchinfo;
 
-       /* Check for obvious errors */
-       /* This match is valid in all hooks! */
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
-               return 0;
-
        /* invflags is 0 or 0xff in hard mode */
        if ((!info->modeflag) && info->invflags != 0x00 &&
            info->invflags != 0xFF)
@@ -147,6 +144,7 @@ ipv6header_checkentry(const char *tablename,
 static struct ip6t_match ip6t_ipv6header_match = {
        .name           = "ipv6header",
        .match          = &ipv6header_match,
+       .matchsize      = sizeof(struct ip6t_ipv6header_info),
        .checkentry     = &ipv6header_checkentry,
        .destroy        = NULL,
        .me             = THIS_MODULE,
index 49f7829..752b65d 100644 (file)
@@ -51,6 +51,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -85,6 +86,7 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *info,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
@@ -92,13 +94,9 @@ checkentry(const char *tablename,
        const struct ip6t_ip6 *ip = info;
        const struct ip6t_multiport *multiinfo = matchinfo;
 
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport)))
-               return 0;
-
        /* Must specify proto == TCP/UDP, no unknown flags or bad count */
        return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
                && !(ip->invflags & IP6T_INV_PROTO)
-               && matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport))
                && (multiinfo->flags == IP6T_MULTIPORT_SOURCE
                    || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
                    || multiinfo->flags == IP6T_MULTIPORT_EITHER)
@@ -107,8 +105,9 @@ checkentry(const char *tablename,
 
 static struct ip6t_match multiport_match = {
        .name           = "multiport",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_multiport),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 8c8a4c7..e2cee3b 100644 (file)
@@ -26,6 +26,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -54,34 +55,27 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *ip,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
        const struct ip6t_owner_info *info = matchinfo;
 
-       if (hook_mask
-           & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) {
-               printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
-               return 0;
-       }
-
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info)))
-               return 0;
-
        if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) {
                printk("ipt_owner: pid and sid matching "
                       "not supported anymore\n");
                return 0;
        }
-
        return 1;
 }
 
 static struct ip6t_match owner_match = {
        .name           = "owner",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_owner_info),
+       .hooks          = (1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c
deleted file mode 100644 (file)
index 3d39ec9..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/* IP tables module for matching IPsec policy
- *
- * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <net/xfrm.h>
-
-#include <linux/netfilter_ipv6.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_policy.h>
-
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_DESCRIPTION("IPtables IPsec policy matching module");
-MODULE_LICENSE("GPL");
-
-
-static inline int
-match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e)
-{
-#define MATCH_ADDR(x,y,z)      (!e->match.x ||                                \
-                                ((!ip6_masked_addrcmp(&e->x.a6, &e->y.a6, z)) \
-                                 ^ e->invert.x))
-#define MATCH(x,y)             (!e->match.x || ((e->x == (y)) ^ e->invert.x))
-       
-       return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) &&
-              MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) &&
-              MATCH(proto, x->id.proto) &&
-              MATCH(mode, x->props.mode) &&
-              MATCH(spi, x->id.spi) &&
-              MATCH(reqid, x->props.reqid);
-}
-
-static int
-match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info)
-{
-       const struct ip6t_policy_elem *e;
-       struct sec_path *sp = skb->sp;
-       int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
-       int i, pos;
-
-       if (sp == NULL)
-               return -1;
-       if (strict && info->len != sp->len)
-               return 0;
-
-       for (i = sp->len - 1; i >= 0; i--) {
-               pos = strict ? i - sp->len + 1 : 0;
-               if (pos >= info->len)
-                       return 0;
-               e = &info->pol[pos];
-
-               if (match_xfrm_state(sp->x[i].xvec, e)) {
-                       if (!strict)
-                               return 1;
-               } else if (strict)
-                       return 0;
-       }
-
-       return strict ? 1 : 0;
-}
-
-static int
-match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info)
-{
-       const struct ip6t_policy_elem *e;
-       struct dst_entry *dst = skb->dst;
-       int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
-       int i, pos;
-
-       if (dst->xfrm == NULL)
-               return -1;
-
-       for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
-               pos = strict ? i : 0;
-               if (pos >= info->len)
-                       return 0;
-               e = &info->pol[pos];
-
-               if (match_xfrm_state(dst->xfrm, e)) {
-                       if (!strict)
-                               return 1;
-               } else if (strict)
-                       return 0;
-       }
-
-       return strict ? i == info->len : 0;
-}
-
-static int match(const struct sk_buff *skb,
-                 const struct net_device *in,
-                 const struct net_device *out,
-                 const void *matchinfo,
-                int offset,
-                unsigned int protoff,
-                int *hotdrop)
-{
-       const struct ip6t_policy_info *info = matchinfo;
-       int ret;
-
-       if (info->flags & IP6T_POLICY_MATCH_IN)
-               ret = match_policy_in(skb, info);
-       else
-               ret = match_policy_out(skb, info);
-
-       if (ret < 0)
-               ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0;
-       else if (info->flags & IP6T_POLICY_MATCH_NONE)
-               ret = 0;
-
-       return ret;
-}
-
-static int checkentry(const char *tablename, const void *ip_void,
-                      void *matchinfo, unsigned int matchsize,
-                      unsigned int hook_mask)
-{
-       struct ip6t_policy_info *info = matchinfo;
-
-       if (matchsize != IP6T_ALIGN(sizeof(*info))) {
-               printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n",
-                      matchsize, IP6T_ALIGN(sizeof(*info)));
-               return 0;
-       }
-       if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) {
-               printk(KERN_ERR "ip6t_policy: neither incoming nor "
-                               "outgoing policy selected\n");
-               return 0;
-       }
-       if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN)
-           && info->flags & IP6T_POLICY_MATCH_OUT) {
-               printk(KERN_ERR "ip6t_policy: output policy not valid in "
-                               "PRE_ROUTING and INPUT\n");
-               return 0;
-       }
-       if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT)
-           && info->flags & IP6T_POLICY_MATCH_IN) {
-               printk(KERN_ERR "ip6t_policy: input policy not valid in "
-                               "POST_ROUTING and OUTPUT\n");
-               return 0;
-       }
-       if (info->len > IP6T_POLICY_MAX_ELEM) {
-               printk(KERN_ERR "ip6t_policy: too many policy elements\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ip6t_match policy_match = {
-       .name           = "policy",
-       .match          = match,
-       .checkentry     = checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ip6t_register_match(&policy_match);
-}
-
-static void __exit fini(void)
-{
-       ip6t_unregister_match(&policy_match);
-}
-
-module_init(init);
-module_exit(fini);
index 8f82476..4c6b55b 100644 (file)
@@ -45,6 +45,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -194,17 +195,13 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *entry,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ip6t_rt *rtinfo = matchinfo;
 
-       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) {
-               DEBUGP("ip6t_rt: matchsize %u != %u\n",
-                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt)));
-               return 0;
-       }
        if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
                DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags);
                return 0;
@@ -222,8 +219,9 @@ checkentry(const char *tablename,
 
 static struct ip6t_match rt_match = {
        .name           = "rt",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct ip6t_rt),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index ac702a2..ac35f95 100644 (file)
@@ -179,31 +179,36 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
                                 int (*okfn)(struct sk_buff *))
 {
        struct nf_conn *ct;
+       struct nf_conn_help *help;
        enum ip_conntrack_info ctinfo;
+       unsigned int ret, protoff;
+       unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
+                             - (*pskb)->data;
+       unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
+
 
        /* This is where we call the helper: as the packet goes out. */
        ct = nf_ct_get(*pskb, &ctinfo);
-       if (ct && ct->helper) {
-               unsigned int ret, protoff;
-               unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
-                                     - (*pskb)->data;
-               unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
-
-               protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
-                                                (*pskb)->len - extoff);
-               if (protoff < 0 || protoff > (*pskb)->len ||
-                   pnum == NEXTHDR_FRAGMENT) {
-                       DEBUGP("proto header not found\n");
-                       return NF_ACCEPT;
-               }
+       if (!ct)
+               goto out;
 
-               ret = ct->helper->help(pskb, protoff, ct, ctinfo);
-               if (ret != NF_ACCEPT)
-                       return ret;
+       help = nfct_help(ct);
+       if (!help || !help->helper)
+               goto out;
+
+       protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
+                                        (*pskb)->len - extoff);
+       if (protoff < 0 || protoff > (*pskb)->len ||
+           pnum == NEXTHDR_FRAGMENT) {
+               DEBUGP("proto header not found\n");
+               return NF_ACCEPT;
        }
 
+       ret = help->helper->help(pskb, protoff, ct, ctinfo);
+       if (ret != NF_ACCEPT)
+               return ret;
+out:
        /* We've seen it coming out the other side: confirm it */
-
        return nf_conntrack_confirm(pskb);
 }
 
index 84ef9a1..3e31903 100644 (file)
@@ -313,8 +313,8 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
 #ifdef CONFIG_SMP
        hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
                if (fq->id == fq_in->id && 
-                   !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) &&
-                   !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) {
+                   ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
+                   ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
                        atomic_inc(&fq->refcnt);
                        write_unlock(&nf_ct_frag6_lock);
                        fq_in->last_in |= COMPLETE;
@@ -376,8 +376,8 @@ fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
        read_lock(&nf_ct_frag6_lock);
        hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
                if (fq->id == id && 
-                   !ipv6_addr_cmp(src, &fq->saddr) &&
-                   !ipv6_addr_cmp(dst, &fq->daddr)) {
+                   ipv6_addr_equal(src, &fq->saddr) &&
+                   ipv6_addr_equal(dst, &fq->daddr)) {
                        atomic_inc(&fq->refcnt);
                        read_unlock(&nf_ct_frag6_lock);
                        return fq;
index ae20a0e..fa1ce0a 100644 (file)
@@ -859,29 +859,12 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
 }
 
 
-static int rawv6_setsockopt(struct sock *sk, int level, int optname, 
+static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
                            char __user *optval, int optlen)
 {
        struct raw6_sock *rp = raw6_sk(sk);
        int val;
 
-       switch(level) {
-               case SOL_RAW:
-                       break;
-
-               case SOL_ICMPV6:
-                       if (inet_sk(sk)->num != IPPROTO_ICMPV6)
-                               return -EOPNOTSUPP;
-                       return rawv6_seticmpfilter(sk, level, optname, optval,
-                                                  optlen);
-               case SOL_IPV6:
-                       if (optname == IPV6_CHECKSUM)
-                               break;
-               default:
-                       return ipv6_setsockopt(sk, level, optname, optval,
-                                              optlen);
-       };
-
        if (get_user(val, (int __user *)optval))
                return -EFAULT;
 
@@ -906,12 +889,9 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
        }
 }
 
-static int rawv6_getsockopt(struct sock *sk, int level, int optname, 
-                           char __user *optval, int __user *optlen)
+static int rawv6_setsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int optlen)
 {
-       struct raw6_sock *rp = raw6_sk(sk);
-       int val, len;
-
        switch(level) {
                case SOL_RAW:
                        break;
@@ -919,15 +899,45 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
                case SOL_ICMPV6:
                        if (inet_sk(sk)->num != IPPROTO_ICMPV6)
                                return -EOPNOTSUPP;
-                       return rawv6_geticmpfilter(sk, level, optname, optval,
+                       return rawv6_seticmpfilter(sk, level, optname, optval,
                                                   optlen);
                case SOL_IPV6:
                        if (optname == IPV6_CHECKSUM)
                                break;
                default:
-                       return ipv6_getsockopt(sk, level, optname, optval,
+                       return ipv6_setsockopt(sk, level, optname, optval,
                                               optlen);
        };
+       return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname,
+                                  char __user *optval, int optlen)
+{
+       switch (level) {
+       case SOL_RAW:
+               break;
+       case SOL_ICMPV6:
+               if (inet_sk(sk)->num != IPPROTO_ICMPV6)
+                       return -EOPNOTSUPP;
+               return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
+       case SOL_IPV6:
+               if (optname == IPV6_CHECKSUM)
+                       break;
+       default:
+               return compat_ipv6_setsockopt(sk, level, optname,
+                                             optval, optlen);
+       };
+       return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
+static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
+                           char __user *optval, int __user *optlen)
+{
+       struct raw6_sock *rp = raw6_sk(sk);
+       int val, len;
 
        if (get_user(len,optlen))
                return -EFAULT;
@@ -953,6 +963,50 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
        return 0;
 }
 
+static int rawv6_getsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       switch(level) {
+               case SOL_RAW:
+                       break;
+
+               case SOL_ICMPV6:
+                       if (inet_sk(sk)->num != IPPROTO_ICMPV6)
+                               return -EOPNOTSUPP;
+                       return rawv6_geticmpfilter(sk, level, optname, optval,
+                                                  optlen);
+               case SOL_IPV6:
+                       if (optname == IPV6_CHECKSUM)
+                               break;
+               default:
+                       return ipv6_getsockopt(sk, level, optname, optval,
+                                              optlen);
+       };
+       return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname,
+                                  char __user *optval, int __user *optlen)
+{
+       switch (level) {
+       case SOL_RAW:
+               break;
+       case SOL_ICMPV6:
+               if (inet_sk(sk)->num != IPPROTO_ICMPV6)
+                       return -EOPNOTSUPP;
+               return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
+       case SOL_IPV6:
+               if (optname == IPV6_CHECKSUM)
+                       break;
+       default:
+               return compat_ipv6_getsockopt(sk, level, optname,
+                                             optval, optlen);
+       };
+       return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
 static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        switch(cmd) {
@@ -998,23 +1052,27 @@ static int rawv6_init_sk(struct sock *sk)
 }
 
 struct proto rawv6_prot = {
-       .name =         "RAWv6",
-       .owner =        THIS_MODULE,
-       .close =        rawv6_close,
-       .connect =      ip6_datagram_connect,
-       .disconnect =   udp_disconnect,
-       .ioctl =        rawv6_ioctl,
-       .init =         rawv6_init_sk,
-       .destroy =      inet6_destroy_sock,
-       .setsockopt =   rawv6_setsockopt,
-       .getsockopt =   rawv6_getsockopt,
-       .sendmsg =      rawv6_sendmsg,
-       .recvmsg =      rawv6_recvmsg,
-       .bind =         rawv6_bind,
-       .backlog_rcv =  rawv6_rcv_skb,
-       .hash =         raw_v6_hash,
-       .unhash =       raw_v6_unhash,
-       .obj_size =     sizeof(struct raw6_sock),
+       .name              = "RAWv6",
+       .owner             = THIS_MODULE,
+       .close             = rawv6_close,
+       .connect           = ip6_datagram_connect,
+       .disconnect        = udp_disconnect,
+       .ioctl             = rawv6_ioctl,
+       .init              = rawv6_init_sk,
+       .destroy           = inet6_destroy_sock,
+       .setsockopt        = rawv6_setsockopt,
+       .getsockopt        = rawv6_getsockopt,
+       .sendmsg           = rawv6_sendmsg,
+       .recvmsg           = rawv6_recvmsg,
+       .bind              = rawv6_bind,
+       .backlog_rcv       = rawv6_rcv_skb,
+       .hash              = raw_v6_hash,
+       .unhash            = raw_v6_unhash,
+       .obj_size          = sizeof(struct raw6_sock),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_rawv6_setsockopt,
+       .compat_getsockopt = compat_rawv6_getsockopt,
+#endif
 };
 
 #ifdef CONFIG_PROC_FS
@@ -1140,7 +1198,7 @@ static int raw6_seq_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct raw6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct raw6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
        if (!s)
                goto out;
        rc = seq_open(file, &raw6_seq_ops);
@@ -1148,7 +1206,6 @@ static int raw6_seq_open(struct inode *inode, struct file *file)
                goto out_kfree;
        seq = file->private_data;
        seq->private = s;
-       memset(s, 0, sizeof(*s));
 out:
        return rc;
 out_kfree:
index 15e1456..b67a45f 100644 (file)
@@ -203,7 +203,7 @@ static inline void frag_free_queue(struct frag_queue *fq, int *work)
 
 static inline struct frag_queue *frag_alloc_queue(void)
 {
-       struct frag_queue *fq = kmalloc(sizeof(struct frag_queue), GFP_ATOMIC);
+       struct frag_queue *fq = kzalloc(sizeof(struct frag_queue), GFP_ATOMIC);
 
        if(!fq)
                return NULL;
@@ -288,6 +288,7 @@ static void ip6_evictor(void)
 static void ip6_frag_expire(unsigned long data)
 {
        struct frag_queue *fq = (struct frag_queue *) data;
+       struct net_device *dev;
 
        spin_lock(&fq->lock);
 
@@ -299,22 +300,22 @@ static void ip6_frag_expire(unsigned long data)
        IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
        IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
 
-       /* Send error only if the first segment arrived. */
-       if (fq->last_in&FIRST_IN && fq->fragments) {
-               struct net_device *dev = dev_get_by_index(fq->iif);
+       /* Don't send error if the first segment did not arrive. */
+       if (!(fq->last_in&FIRST_IN) || !fq->fragments)
+               goto out;
 
-               /*
-                  But use as source device on which LAST ARRIVED
-                  segment was received. And do not use fq->dev
-                  pointer directly, device might already disappeared.
-                */
-               if (dev) {
-                       fq->fragments->dev = dev;
-                       icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0,
-                                   dev);
-                       dev_put(dev);
-               }
-       }
+       dev = dev_get_by_index(fq->iif);
+       if (!dev)
+               goto out;
+
+       /*
+          But use as source device on which LAST ARRIVED
+          segment was received. And do not use fq->dev
+          pointer directly, device might already disappeared.
+        */
+       fq->fragments->dev = dev;
+       icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
+       dev_put(dev);
 out:
        spin_unlock(&fq->lock);
        fq_put(fq, NULL);
@@ -368,8 +369,6 @@ ip6_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr
        if ((fq = frag_alloc_queue()) == NULL)
                goto oom;
 
-       memset(fq, 0, sizeof(struct frag_queue));
-
        fq->id = id;
        ipv6_addr_copy(&fq->saddr, src);
        ipv6_addr_copy(&fq->daddr, dst);
index e0d3ad0..7907874 100644 (file)
 #define RT6_TRACE(x...) do { ; } while (0)
 #endif
 
+#define CLONE_OFFLINK_ROUTE 0
+
+#define RT6_SELECT_F_IFACE     0x1
+#define RT6_SELECT_F_REACHABLE 0x2
 
 static int ip6_rt_max_size = 4096;
 static int ip6_rt_gc_min_interval = HZ / 2;
@@ -94,6 +98,14 @@ static int           ip6_pkt_discard_out(struct sk_buff *skb);
 static void            ip6_link_failure(struct sk_buff *skb);
 static void            ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
 
+#ifdef CONFIG_IPV6_ROUTE_INFO
+static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
+                                          struct in6_addr *gwaddr, int ifindex,
+                                          unsigned pref);
+static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
+                                          struct in6_addr *gwaddr, int ifindex);
+#endif
+
 static struct dst_ops ip6_dst_ops = {
        .family                 =       AF_INET6,
        .protocol               =       __constant_htons(ETH_P_IPV6),
@@ -214,150 +226,211 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
        return rt;
 }
 
+#ifdef CONFIG_IPV6_ROUTER_PREF
+static void rt6_probe(struct rt6_info *rt)
+{
+       struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL;
+       /*
+        * Okay, this does not seem to be appropriate
+        * for now, however, we need to check if it
+        * is really so; aka Router Reachability Probing.
+        *
+        * Router Reachability Probe MUST be rate-limited
+        * to no more than one per minute.
+        */
+       if (!neigh || (neigh->nud_state & NUD_VALID))
+               return;
+       read_lock_bh(&neigh->lock);
+       if (!(neigh->nud_state & NUD_VALID) &&
+           time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
+               struct in6_addr mcaddr;
+               struct in6_addr *target;
+
+               neigh->updated = jiffies;
+               read_unlock_bh(&neigh->lock);
+
+               target = (struct in6_addr *)&neigh->primary_key;
+               addrconf_addr_solict_mult(target, &mcaddr);
+               ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL);
+       } else
+               read_unlock_bh(&neigh->lock);
+}
+#else
+static inline void rt6_probe(struct rt6_info *rt)
+{
+       return;
+}
+#endif
+
 /*
- *     pointer to the last default router chosen. BH is disabled locally.
+ * Default Router Selection (RFC 2461 6.3.6)
  */
-static struct rt6_info *rt6_dflt_pointer;
-static DEFINE_SPINLOCK(rt6_dflt_lock);
+static int inline rt6_check_dev(struct rt6_info *rt, int oif)
+{
+       struct net_device *dev = rt->rt6i_dev;
+       if (!oif || dev->ifindex == oif)
+               return 2;
+       if ((dev->flags & IFF_LOOPBACK) &&
+           rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
+               return 1;
+       return 0;
+}
 
-void rt6_reset_dflt_pointer(struct rt6_info *rt)
+static int inline rt6_check_neigh(struct rt6_info *rt)
 {
-       spin_lock_bh(&rt6_dflt_lock);
-       if (rt == NULL || rt == rt6_dflt_pointer) {
-               RT6_TRACE("reset default router: %p->NULL\n", rt6_dflt_pointer);
-               rt6_dflt_pointer = NULL;
+       struct neighbour *neigh = rt->rt6i_nexthop;
+       int m = 0;
+       if (neigh) {
+               read_lock_bh(&neigh->lock);
+               if (neigh->nud_state & NUD_VALID)
+                       m = 1;
+               read_unlock_bh(&neigh->lock);
        }
-       spin_unlock_bh(&rt6_dflt_lock);
+       return m;
 }
 
-/* Default Router Selection (RFC 2461 6.3.6) */
-static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif)
+static int rt6_score_route(struct rt6_info *rt, int oif,
+                          int strict)
 {
-       struct rt6_info *match = NULL;
-       struct rt6_info *sprt;
-       int mpri = 0;
-
-       for (sprt = rt; sprt; sprt = sprt->u.next) {
-               struct neighbour *neigh;
-               int m = 0;
-
-               if (!oif ||
-                   (sprt->rt6i_dev &&
-                    sprt->rt6i_dev->ifindex == oif))
-                       m += 8;
+       int m = rt6_check_dev(rt, oif);
+       if (!m && (strict & RT6_SELECT_F_IFACE))
+               return -1;
+#ifdef CONFIG_IPV6_ROUTER_PREF
+       m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
+#endif
+       if (rt6_check_neigh(rt))
+               m |= 16;
+       else if (strict & RT6_SELECT_F_REACHABLE)
+               return -1;
+       return m;
+}
 
-               if (rt6_check_expired(sprt))
-                       continue;
+static struct rt6_info *rt6_select(struct rt6_info **head, int oif,
+                                  int strict)
+{
+       struct rt6_info *match = NULL, *last = NULL;
+       struct rt6_info *rt, *rt0 = *head;
+       u32 metric;
+       int mpri = -1;
 
-               if (sprt == rt6_dflt_pointer)
-                       m += 4;
+       RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n",
+                 __FUNCTION__, head, head ? *head : NULL, oif);
 
-               if ((neigh = sprt->rt6i_nexthop) != NULL) {
-                       read_lock_bh(&neigh->lock);
-                       switch (neigh->nud_state) {
-                       case NUD_REACHABLE:
-                               m += 3;
-                               break;
+       for (rt = rt0, metric = rt0->rt6i_metric;
+            rt && rt->rt6i_metric == metric;
+            rt = rt->u.next) {
+               int m;
 
-                       case NUD_STALE:
-                       case NUD_DELAY:
-                       case NUD_PROBE:
-                               m += 2;
-                               break;
+               if (rt6_check_expired(rt))
+                       continue;
 
-                       case NUD_NOARP:
-                       case NUD_PERMANENT:
-                               m += 1;
-                               break;
+               last = rt;
 
-                       case NUD_INCOMPLETE:
-                       default:
-                               read_unlock_bh(&neigh->lock);
-                               continue;
-                       }
-                       read_unlock_bh(&neigh->lock);
-               } else {
+               m = rt6_score_route(rt, oif, strict);
+               if (m < 0)
                        continue;
-               }
 
-               if (m > mpri || m >= 12) {
-                       match = sprt;
+               if (m > mpri) {
+                       rt6_probe(match);
+                       match = rt;
                        mpri = m;
-                       if (m >= 12) {
-                               /* we choose the last default router if it
-                                * is in (probably) reachable state.
-                                * If route changed, we should do pmtu
-                                * discovery. --yoshfuji
-                                */
-                               break;
-                       }
+               } else {
+                       rt6_probe(rt);
                }
        }
 
-       spin_lock(&rt6_dflt_lock);
-       if (!match) {
-               /*
-                *      No default routers are known to be reachable.
-                *      SHOULD round robin
-                */
-               if (rt6_dflt_pointer) {
-                       for (sprt = rt6_dflt_pointer->u.next;
-                            sprt; sprt = sprt->u.next) {
-                               if (sprt->u.dst.obsolete <= 0 &&
-                                   sprt->u.dst.error == 0 &&
-                                   !rt6_check_expired(sprt)) {
-                                       match = sprt;
-                                       break;
-                               }
-                       }
-                       for (sprt = rt;
-                            !match && sprt;
-                            sprt = sprt->u.next) {
-                               if (sprt->u.dst.obsolete <= 0 &&
-                                   sprt->u.dst.error == 0 &&
-                                   !rt6_check_expired(sprt)) {
-                                       match = sprt;
-                                       break;
-                               }
-                               if (sprt == rt6_dflt_pointer)
-                                       break;
-                       }
-               }
+       if (!match &&
+           (strict & RT6_SELECT_F_REACHABLE) &&
+           last && last != rt0) {
+               /* no entries matched; do round-robin */
+               *head = rt0->u.next;
+               rt0->u.next = last->u.next;
+               last->u.next = rt0;
        }
 
-       if (match) {
-               if (rt6_dflt_pointer != match)
-                       RT6_TRACE("changed default router: %p->%p\n",
-                                 rt6_dflt_pointer, match);
-               rt6_dflt_pointer = match;
+       RT6_TRACE("%s() => %p, score=%d\n",
+                 __FUNCTION__, match, mpri);
+
+       return (match ? match : &ip6_null_entry);
+}
+
+#ifdef CONFIG_IPV6_ROUTE_INFO
+int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
+                 struct in6_addr *gwaddr)
+{
+       struct route_info *rinfo = (struct route_info *) opt;
+       struct in6_addr prefix_buf, *prefix;
+       unsigned int pref;
+       u32 lifetime;
+       struct rt6_info *rt;
+
+       if (len < sizeof(struct route_info)) {
+               return -EINVAL;
        }
-       spin_unlock(&rt6_dflt_lock);
 
-       if (!match) {
-               /*
-                * Last Resort: if no default routers found, 
-                * use addrconf default route.
-                * We don't record this route.
-                */
-               for (sprt = ip6_routing_table.leaf;
-                    sprt; sprt = sprt->u.next) {
-                       if (!rt6_check_expired(sprt) &&
-                           (sprt->rt6i_flags & RTF_DEFAULT) &&
-                           (!oif ||
-                            (sprt->rt6i_dev &&
-                             sprt->rt6i_dev->ifindex == oif))) {
-                               match = sprt;
-                               break;
-                       }
+       /* Sanity check for prefix_len and length */
+       if (rinfo->length > 3) {
+               return -EINVAL;
+       } else if (rinfo->prefix_len > 128) {
+               return -EINVAL;
+       } else if (rinfo->prefix_len > 64) {
+               if (rinfo->length < 2) {
+                       return -EINVAL;
                }
-               if (!match) {
-                       /* no default route.  give up. */
-                       match = &ip6_null_entry;
+       } else if (rinfo->prefix_len > 0) {
+               if (rinfo->length < 1) {
+                       return -EINVAL;
                }
        }
 
-       return match;
+       pref = rinfo->route_pref;
+       if (pref == ICMPV6_ROUTER_PREF_INVALID)
+               pref = ICMPV6_ROUTER_PREF_MEDIUM;
+
+       lifetime = htonl(rinfo->lifetime);
+       if (lifetime == 0xffffffff) {
+               /* infinity */
+       } else if (lifetime > 0x7fffffff/HZ) {
+               /* Avoid arithmetic overflow */
+               lifetime = 0x7fffffff/HZ - 1;
+       }
+
+       if (rinfo->length == 3)
+               prefix = (struct in6_addr *)rinfo->prefix;
+       else {
+               /* this function is safe */
+               ipv6_addr_prefix(&prefix_buf,
+                                (struct in6_addr *)rinfo->prefix,
+                                rinfo->prefix_len);
+               prefix = &prefix_buf;
+       }
+
+       rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex);
+
+       if (rt && !lifetime) {
+               ip6_del_rt(rt, NULL, NULL, NULL);
+               rt = NULL;
+       }
+
+       if (!rt && lifetime)
+               rt = rt6_add_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
+                                       pref);
+       else if (rt)
+               rt->rt6i_flags = RTF_ROUTEINFO |
+                                (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
+
+       if (rt) {
+               if (lifetime == 0xffffffff) {
+                       rt->rt6i_flags &= ~RTF_EXPIRES;
+               } else {
+                       rt->rt6i_expires = jiffies + HZ * lifetime;
+                       rt->rt6i_flags |= RTF_EXPIRES;
+               }
+               dst_release(&rt->u.dst);
+       }
+       return 0;
 }
+#endif
 
 struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
                            int oif, int strict)
@@ -397,14 +470,9 @@ int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh,
        return err;
 }
 
-/* No rt6_lock! If COW failed, the function returns dead route entry
-   with dst->error set to errno value.
- */
-
-static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
-                               struct in6_addr *saddr, struct netlink_skb_parms *req)
+static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr,
+                                     struct in6_addr *saddr)
 {
-       int err;
        struct rt6_info *rt;
 
        /*
@@ -435,25 +503,30 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
 
                rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
 
-               dst_hold(&rt->u.dst);
-
-               err = ip6_ins_rt(rt, NULL, NULL, req);
-               if (err == 0)
-                       return rt;
+       }
 
-               rt->u.dst.error = err;
+       return rt;
+}
 
-               return rt;
+static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr)
+{
+       struct rt6_info *rt = ip6_rt_copy(ort);
+       if (rt) {
+               ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
+               rt->rt6i_dst.plen = 128;
+               rt->rt6i_flags |= RTF_CACHE;
+               if (rt->rt6i_flags & RTF_REJECT)
+                       rt->u.dst.error = ort->u.dst.error;
+               rt->u.dst.flags |= DST_HOST;
+               rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
        }
-       dst_hold(&ip6_null_entry.u.dst);
-       return &ip6_null_entry;
+       return rt;
 }
 
 #define BACKTRACK() \
-if (rt == &ip6_null_entry && strict) { \
+if (rt == &ip6_null_entry) { \
        while ((fn = fn->parent) != NULL) { \
                if (fn->fn_flags & RTN_ROOT) { \
-                       dst_hold(&rt->u.dst); \
                        goto out; \
                } \
                if (fn->fn_flags & RTN_RTINFO) \
@@ -465,115 +538,138 @@ if (rt == &ip6_null_entry && strict) { \
 void ip6_route_input(struct sk_buff *skb)
 {
        struct fib6_node *fn;
-       struct rt6_info *rt;
+       struct rt6_info *rt, *nrt;
        int strict;
        int attempts = 3;
+       int err;
+       int reachable = RT6_SELECT_F_REACHABLE;
 
-       strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
+       strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0;
 
 relookup:
        read_lock_bh(&rt6_lock);
 
+restart_2:
        fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr,
                         &skb->nh.ipv6h->saddr);
 
 restart:
-       rt = fn->leaf;
-
-       if ((rt->rt6i_flags & RTF_CACHE)) {
-               rt = rt6_device_match(rt, skb->dev->ifindex, strict);
-               BACKTRACK();
-               dst_hold(&rt->u.dst);
-               goto out;
-       }
-
-       rt = rt6_device_match(rt, skb->dev->ifindex, strict);
+       rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable);
        BACKTRACK();
+       if (rt == &ip6_null_entry ||
+           rt->rt6i_flags & RTF_CACHE)
+               goto out;
 
-       if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-               struct rt6_info *nrt;
-               dst_hold(&rt->u.dst);
-               read_unlock_bh(&rt6_lock);
+       dst_hold(&rt->u.dst);
+       read_unlock_bh(&rt6_lock);
 
-               nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
-                             &skb->nh.ipv6h->saddr,
-                             &NETLINK_CB(skb));
+       if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+               nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr);
+       else {
+#if CLONE_OFFLINK_ROUTE
+               nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr);
+#else
+               goto out2;
+#endif
+       }
 
-               dst_release(&rt->u.dst);
-               rt = nrt;
+       dst_release(&rt->u.dst);
+       rt = nrt ? : &ip6_null_entry;
 
-               if (rt->u.dst.error != -EEXIST || --attempts <= 0)
+       dst_hold(&rt->u.dst);
+       if (nrt) {
+               err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb));
+               if (!err)
                        goto out2;
-
-               /* Race condition! In the gap, when rt6_lock was
-                  released someone could insert this route.  Relookup.
-               */
-               dst_release(&rt->u.dst);
-               goto relookup;
        }
-       dst_hold(&rt->u.dst);
+
+       if (--attempts <= 0)
+               goto out2;
+
+       /*
+        * Race condition! In the gap, when rt6_lock was
+        * released someone could insert this route.  Relookup.
+        */
+       dst_release(&rt->u.dst);
+       goto relookup;
 
 out:
+       if (reachable) {
+               reachable = 0;
+               goto restart_2;
+       }
+       dst_hold(&rt->u.dst);
        read_unlock_bh(&rt6_lock);
 out2:
        rt->u.dst.lastuse = jiffies;
        rt->u.dst.__use++;
        skb->dst = (struct dst_entry *) rt;
+       return;
 }
 
 struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
 {
        struct fib6_node *fn;
-       struct rt6_info *rt;
+       struct rt6_info *rt, *nrt;
        int strict;
        int attempts = 3;
+       int err;
+       int reachable = RT6_SELECT_F_REACHABLE;
 
-       strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
+       strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0;
 
 relookup:
        read_lock_bh(&rt6_lock);
 
+restart_2:
        fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src);
 
 restart:
-       rt = fn->leaf;
-
-       if ((rt->rt6i_flags & RTF_CACHE)) {
-               rt = rt6_device_match(rt, fl->oif, strict);
-               BACKTRACK();
-               dst_hold(&rt->u.dst);
+       rt = rt6_select(&fn->leaf, fl->oif, strict | reachable);
+       BACKTRACK();
+       if (rt == &ip6_null_entry ||
+           rt->rt6i_flags & RTF_CACHE)
                goto out;
-       }
-       if (rt->rt6i_flags & RTF_DEFAULT) {
-               if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
-                       rt = rt6_best_dflt(rt, fl->oif);
-       } else {
-               rt = rt6_device_match(rt, fl->oif, strict);
-               BACKTRACK();
-       }
 
-       if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-               struct rt6_info *nrt;
-               dst_hold(&rt->u.dst);
-               read_unlock_bh(&rt6_lock);
+       dst_hold(&rt->u.dst);
+       read_unlock_bh(&rt6_lock);
 
-               nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src, NULL);
+       if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+               nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
+       else {
+#if CLONE_OFFLINK_ROUTE
+               nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
+#else
+               goto out2;
+#endif
+       }
 
-               dst_release(&rt->u.dst);
-               rt = nrt;
+       dst_release(&rt->u.dst);
+       rt = nrt ? : &ip6_null_entry;
 
-               if (rt->u.dst.error != -EEXIST || --attempts <= 0)
+       dst_hold(&rt->u.dst);
+       if (nrt) {
+               err = ip6_ins_rt(nrt, NULL, NULL, NULL);
+               if (!err)
                        goto out2;
-
-               /* Race condition! In the gap, when rt6_lock was
-                  released someone could insert this route.  Relookup.
-               */
-               dst_release(&rt->u.dst);
-               goto relookup;
        }
-       dst_hold(&rt->u.dst);
+
+       if (--attempts <= 0)
+               goto out2;
+
+       /*
+        * Race condition! In the gap, when rt6_lock was
+        * released someone could insert this route.  Relookup.
+        */
+       dst_release(&rt->u.dst);
+       goto relookup;
 
 out:
+       if (reachable) {
+               reachable = 0;
+               goto restart_2;
+       }
+       dst_hold(&rt->u.dst);
        read_unlock_bh(&rt6_lock);
 out2:
        rt->u.dst.lastuse = jiffies;
@@ -999,8 +1095,6 @@ int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct
 
        write_lock_bh(&rt6_lock);
 
-       rt6_reset_dflt_pointer(NULL);
-
        err = fib6_del(rt, nlh, _rtattr, req);
        dst_release(&rt->u.dst);
 
@@ -1050,59 +1144,63 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r
 void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
                  struct neighbour *neigh, u8 *lladdr, int on_link)
 {
-       struct rt6_info *rt, *nrt;
-
-       /* Locate old route to this destination. */
-       rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
-
-       if (rt == NULL)
-               return;
-
-       if (neigh->dev != rt->rt6i_dev)
-               goto out;
+       struct rt6_info *rt, *nrt = NULL;
+       int strict;
+       struct fib6_node *fn;
 
        /*
-        * Current route is on-link; redirect is always invalid.
-        * 
-        * Seems, previous statement is not true. It could
-        * be node, which looks for us as on-link (f.e. proxy ndisc)
-        * But then router serving it might decide, that we should
-        * know truth 8)8) --ANK (980726).
+        * Get the "current" route for this destination and
+        * check if the redirect has come from approriate router.
+        *
+        * RFC 2461 specifies that redirects should only be
+        * accepted if they come from the nexthop to the target.
+        * Due to the way the routes are chosen, this notion
+        * is a bit fuzzy and one might need to check all possible
+        * routes.
         */
-       if (!(rt->rt6i_flags&RTF_GATEWAY))
-               goto out;
+       strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL);
 
-       /*
-        *      RFC 2461 specifies that redirects should only be
-        *      accepted if they come from the nexthop to the target.
-        *      Due to the way default routers are chosen, this notion
-        *      is a bit fuzzy and one might need to check all default
-        *      routers.
-        */
-       if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) {
-               if (rt->rt6i_flags & RTF_DEFAULT) {
-                       struct rt6_info *rt1;
-
-                       read_lock(&rt6_lock);
-                       for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) {
-                               if (ipv6_addr_equal(saddr, &rt1->rt6i_gateway)) {
-                                       dst_hold(&rt1->u.dst);
-                                       dst_release(&rt->u.dst);
-                                       read_unlock(&rt6_lock);
-                                       rt = rt1;
-                                       goto source_ok;
-                               }
-                       }
-                       read_unlock(&rt6_lock);
+       read_lock_bh(&rt6_lock);
+       fn = fib6_lookup(&ip6_routing_table, dest, NULL);
+restart:
+       for (rt = fn->leaf; rt; rt = rt->u.next) {
+               /*
+                * Current route is on-link; redirect is always invalid.
+                *
+                * Seems, previous statement is not true. It could
+                * be node, which looks for us as on-link (f.e. proxy ndisc)
+                * But then router serving it might decide, that we should
+                * know truth 8)8) --ANK (980726).
+                */
+               if (rt6_check_expired(rt))
+                       continue;
+               if (!(rt->rt6i_flags & RTF_GATEWAY))
+                       continue;
+               if (neigh->dev != rt->rt6i_dev)
+                       continue;
+               if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway))
+                       continue;
+               break;
+       }
+       if (rt)
+               dst_hold(&rt->u.dst);
+       else if (strict) {
+               while ((fn = fn->parent) != NULL) {
+                       if (fn->fn_flags & RTN_ROOT)
+                               break;
+                       if (fn->fn_flags & RTN_RTINFO)
+                               goto restart;
                }
+       }
+       read_unlock_bh(&rt6_lock);
+
+       if (!rt) {
                if (net_ratelimit())
                        printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
                               "for redirect target\n");
-               goto out;
+               return;
        }
 
-source_ok:
-
        /*
         *      We have finally decided to accept it.
         */
@@ -1210,38 +1308,27 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
           1. It is connected route. Action: COW
           2. It is gatewayed route or NONEXTHOP route. Action: clone it.
         */
-       if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-               nrt = rt6_cow(rt, daddr, saddr, NULL);
-               if (!nrt->u.dst.error) {
-                       nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
-                       if (allfrag)
-                               nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
-                       /* According to RFC 1981, detecting PMTU increase shouldn't be
-                          happened within 5 mins, the recommended timer is 10 mins.
-                          Here this route expiration time is set to ip6_rt_mtu_expires
-                          which is 10 mins. After 10 mins the decreased pmtu is expired
-                          and detecting PMTU increase will be automatically happened.
-                        */
-                       dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
-                       nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
-               }
-               dst_release(&nrt->u.dst);
-       } else {
-               nrt = ip6_rt_copy(rt);
-               if (nrt == NULL)
-                       goto out;
-               ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
-               nrt->rt6i_dst.plen = 128;
-               nrt->u.dst.flags |= DST_HOST;
-               nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);
-               dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
-               nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
+       if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
+               nrt = rt6_alloc_cow(rt, daddr, saddr);
+       else
+               nrt = rt6_alloc_clone(rt, daddr);
+
+       if (nrt) {
                nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
                if (allfrag)
                        nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+
+               /* According to RFC 1981, detecting PMTU increase shouldn't be
+                * happened within 5 mins, the recommended timer is 10 mins.
+                * Here this route expiration time is set to ip6_rt_mtu_expires
+                * which is 10 mins. After 10 mins the decreased pmtu is expired
+                * and detecting PMTU increase will be automatically happened.
+                */
+               dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
+               nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
+
                ip6_ins_rt(nrt, NULL, NULL, NULL);
        }
-
 out:
        dst_release(&rt->u.dst);
 }
@@ -1280,6 +1367,57 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
        return rt;
 }
 
+#ifdef CONFIG_IPV6_ROUTE_INFO
+static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
+                                          struct in6_addr *gwaddr, int ifindex)
+{
+       struct fib6_node *fn;
+       struct rt6_info *rt = NULL;
+
+       write_lock_bh(&rt6_lock);
+       fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0);
+       if (!fn)
+               goto out;
+
+       for (rt = fn->leaf; rt; rt = rt->u.next) {
+               if (rt->rt6i_dev->ifindex != ifindex)
+                       continue;
+               if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
+                       continue;
+               if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
+                       continue;
+               dst_hold(&rt->u.dst);
+               break;
+       }
+out:
+       write_unlock_bh(&rt6_lock);
+       return rt;
+}
+
+static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
+                                          struct in6_addr *gwaddr, int ifindex,
+                                          unsigned pref)
+{
+       struct in6_rtmsg rtmsg;
+
+       memset(&rtmsg, 0, sizeof(rtmsg));
+       rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+       ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix);
+       rtmsg.rtmsg_dst_len = prefixlen;
+       ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
+       rtmsg.rtmsg_metric = 1024;
+       rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref);
+       /* We should treat it as a default route if prefix length is 0. */
+       if (!prefixlen)
+               rtmsg.rtmsg_flags |= RTF_DEFAULT;
+       rtmsg.rtmsg_ifindex = ifindex;
+
+       ip6_route_add(&rtmsg, NULL, NULL, NULL);
+
+       return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex);
+}
+#endif
+
 struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev)
 {      
        struct rt6_info *rt;
@@ -1290,6 +1428,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
        write_lock_bh(&rt6_lock);
        for (rt = fn->leaf; rt; rt=rt->u.next) {
                if (dev == rt->rt6i_dev &&
+                   ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
                    ipv6_addr_equal(&rt->rt6i_gateway, addr))
                        break;
        }
@@ -1300,7 +1439,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
 }
 
 struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
-                                    struct net_device *dev)
+                                    struct net_device *dev,
+                                    unsigned int pref)
 {
        struct in6_rtmsg rtmsg;
 
@@ -1308,7 +1448,8 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
        rtmsg.rtmsg_type = RTMSG_NEWROUTE;
        ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
        rtmsg.rtmsg_metric = 1024;
-       rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES;
+       rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES |
+                           RTF_PREF(pref);
 
        rtmsg.rtmsg_ifindex = dev->ifindex;
 
@@ -1326,8 +1467,6 @@ restart:
                if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
                        dst_hold(&rt->u.dst);
 
-                       rt6_reset_dflt_pointer(NULL);
-
                        read_unlock_bh(&rt6_lock);
 
                        ip6_del_rt(rt, NULL, NULL, NULL);
@@ -1738,11 +1877,10 @@ int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
                /*
                 * 2. allocate and initialize walker.
                 */
-               w = kmalloc(sizeof(*w), GFP_ATOMIC);
+               w = kzalloc(sizeof(*w), GFP_ATOMIC);
                if (w == NULL)
                        return -ENOMEM;
                RT6_TRACE("dump<%p", w);
-               memset(w, 0, sizeof(*w));
                w->root = &ip6_routing_table;
                w->func = fib6_dump_node;
                w->args = &arg;
index ca9cf68..301eee7 100644 (file)
@@ -987,6 +987,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
                                                     newnp->opt->opt_flen);
 
+       tcp_mtup_init(newsk);
        tcp_sync_mss(newsk, dst_mtu(dst));
        newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
        tcp_initialize_rcv_mss(newsk);
@@ -1297,18 +1298,21 @@ static int tcp_v6_remember_stamp(struct sock *sk)
 }
 
 static struct inet_connection_sock_af_ops ipv6_specific = {
-       .queue_xmit     =       inet6_csk_xmit,
-       .send_check     =       tcp_v6_send_check,
-       .rebuild_header =       inet6_sk_rebuild_header,
-       .conn_request   =       tcp_v6_conn_request,
-       .syn_recv_sock  =       tcp_v6_syn_recv_sock,
-       .remember_stamp =       tcp_v6_remember_stamp,
-       .net_header_len =       sizeof(struct ipv6hdr),
-
-       .setsockopt     =       ipv6_setsockopt,
-       .getsockopt     =       ipv6_getsockopt,
-       .addr2sockaddr  =       inet6_csk_addr2sockaddr,
-       .sockaddr_len   =       sizeof(struct sockaddr_in6)
+       .queue_xmit        = inet6_csk_xmit,
+       .send_check        = tcp_v6_send_check,
+       .rebuild_header    = inet6_sk_rebuild_header,
+       .conn_request      = tcp_v6_conn_request,
+       .syn_recv_sock     = tcp_v6_syn_recv_sock,
+       .remember_stamp    = tcp_v6_remember_stamp,
+       .net_header_len    = sizeof(struct ipv6hdr),
+       .setsockopt        = ipv6_setsockopt,
+       .getsockopt        = ipv6_getsockopt,
+       .addr2sockaddr     = inet6_csk_addr2sockaddr,
+       .sockaddr_len      = sizeof(struct sockaddr_in6),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ipv6_setsockopt,
+       .compat_getsockopt = compat_ipv6_getsockopt,
+#endif
 };
 
 /*
@@ -1316,22 +1320,23 @@ static struct inet_connection_sock_af_ops ipv6_specific = {
  */
 
 static struct inet_connection_sock_af_ops ipv6_mapped = {
-       .queue_xmit     =       ip_queue_xmit,
-       .send_check     =       tcp_v4_send_check,
-       .rebuild_header =       inet_sk_rebuild_header,
-       .conn_request   =       tcp_v6_conn_request,
-       .syn_recv_sock  =       tcp_v6_syn_recv_sock,
-       .remember_stamp =       tcp_v4_remember_stamp,
-       .net_header_len =       sizeof(struct iphdr),
-
-       .setsockopt     =       ipv6_setsockopt,
-       .getsockopt     =       ipv6_getsockopt,
-       .addr2sockaddr  =       inet6_csk_addr2sockaddr,
-       .sockaddr_len   =       sizeof(struct sockaddr_in6)
+       .queue_xmit        = ip_queue_xmit,
+       .send_check        = tcp_v4_send_check,
+       .rebuild_header    = inet_sk_rebuild_header,
+       .conn_request      = tcp_v6_conn_request,
+       .syn_recv_sock     = tcp_v6_syn_recv_sock,
+       .remember_stamp    = tcp_v4_remember_stamp,
+       .net_header_len    = sizeof(struct iphdr),
+       .setsockopt        = ipv6_setsockopt,
+       .getsockopt        = ipv6_getsockopt,
+       .addr2sockaddr     = inet6_csk_addr2sockaddr,
+       .sockaddr_len      = sizeof(struct sockaddr_in6),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ipv6_setsockopt,
+       .compat_getsockopt = compat_ipv6_getsockopt,
+#endif
 };
 
-
-
 /* NOTE: A lot of things set to zero explicitly by call to
  *       sk_alloc() so need not be done here.
  */
@@ -1583,6 +1588,10 @@ struct proto tcpv6_prot = {
        .obj_size               = sizeof(struct tcp6_sock),
        .twsk_prot              = &tcp6_timewait_sock_ops,
        .rsk_prot               = &tcp6_request_sock_ops,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt      = compat_tcp_setsockopt,
+       .compat_getsockopt      = compat_tcp_getsockopt,
+#endif
 };
 
 static struct inet6_protocol tcpv6_protocol = {
@@ -1604,21 +1613,12 @@ static struct inet_protosw tcpv6_protosw = {
 
 void __init tcpv6_init(void)
 {
-       int err;
-
        /* register inet6 protocol */
        if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
                printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
        inet6_register_protosw(&tcpv6_protosw);
 
-       err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_TCP, &tcp6_socket);
-       if (err < 0)
+       if (inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, SOCK_RAW,
+                                    IPPROTO_TCP) < 0)
                panic("Failed to create the TCPv6 control socket.\n");
-       tcp6_socket->sk->sk_allocation = GFP_ATOMIC;
-
-       /* Unhash it so that IP input processing does not even
-        * see it, we do not wish this socket to see incoming
-        * packets.
-        */
-       tcp6_socket->sk->sk_prot->unhash(tcp6_socket->sk);
 }
index c476488..8d3432a 100644 (file)
@@ -880,16 +880,13 @@ static int udpv6_destroy_sock(struct sock *sk)
 /*
  *     Socket option code for UDP
  */
-static int udpv6_setsockopt(struct sock *sk, int level, int optname, 
+static int do_udpv6_setsockopt(struct sock *sk, int level, int optname,
                          char __user *optval, int optlen)
 {
        struct udp_sock *up = udp_sk(sk);
        int val;
        int err = 0;
 
-       if (level != SOL_UDP)
-               return ipv6_setsockopt(sk, level, optname, optval, optlen);
-
        if(optlen<sizeof(int))
                return -EINVAL;
 
@@ -927,15 +924,31 @@ static int udpv6_setsockopt(struct sock *sk, int level, int optname,
        return err;
 }
 
-static int udpv6_getsockopt(struct sock *sk, int level, int optname, 
+static int udpv6_setsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int optlen)
+{
+       if (level != SOL_UDP)
+               return ipv6_setsockopt(sk, level, optname, optval, optlen);
+       return do_udpv6_setsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname,
+                                  char __user *optval, int optlen)
+{
+       if (level != SOL_UDP)
+               return compat_ipv6_setsockopt(sk, level, optname,
+                                             optval, optlen);
+       return do_udpv6_setsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
+static int do_udpv6_getsockopt(struct sock *sk, int level, int optname,
                          char __user *optval, int __user *optlen)
 {
        struct udp_sock *up = udp_sk(sk);
        int val, len;
 
-       if (level != SOL_UDP)
-               return ipv6_getsockopt(sk, level, optname, optval, optlen);
-
        if(get_user(len,optlen))
                return -EFAULT;
 
@@ -964,6 +977,25 @@ static int udpv6_getsockopt(struct sock *sk, int level, int optname,
        return 0;
 }
 
+static int udpv6_getsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       if (level != SOL_UDP)
+               return ipv6_getsockopt(sk, level, optname, optval, optlen);
+       return do_udpv6_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
+                                  char __user *optval, int __user *optlen)
+{
+       if (level != SOL_UDP)
+               return compat_ipv6_getsockopt(sk, level, optname,
+                                             optval, optlen);
+       return do_udpv6_getsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
 static struct inet6_protocol udpv6_protocol = {
        .handler        =       udpv6_rcv,
        .err_handler    =       udpv6_err,
@@ -1037,22 +1069,26 @@ void udp6_proc_exit(void) {
 /* ------------------------------------------------------------------------ */
 
 struct proto udpv6_prot = {
-       .name =         "UDPv6",
-       .owner =        THIS_MODULE,
-       .close =        udpv6_close,
-       .connect =      ip6_datagram_connect,
-       .disconnect =   udp_disconnect,
-       .ioctl =        udp_ioctl,
-       .destroy =      udpv6_destroy_sock,
-       .setsockopt =   udpv6_setsockopt,
-       .getsockopt =   udpv6_getsockopt,
-       .sendmsg =      udpv6_sendmsg,
-       .recvmsg =      udpv6_recvmsg,
-       .backlog_rcv =  udpv6_queue_rcv_skb,
-       .hash =         udp_v6_hash,
-       .unhash =       udp_v6_unhash,
-       .get_port =     udp_v6_get_port,
-       .obj_size =     sizeof(struct udp6_sock),
+       .name              = "UDPv6",
+       .owner             = THIS_MODULE,
+       .close             = udpv6_close,
+       .connect           = ip6_datagram_connect,
+       .disconnect        = udp_disconnect,
+       .ioctl             = udp_ioctl,
+       .destroy           = udpv6_destroy_sock,
+       .setsockopt        = udpv6_setsockopt,
+       .getsockopt        = udpv6_getsockopt,
+       .sendmsg           = udpv6_sendmsg,
+       .recvmsg           = udpv6_recvmsg,
+       .backlog_rcv       = udpv6_queue_rcv_skb,
+       .hash              = udp_v6_hash,
+       .unhash            = udp_v6_unhash,
+       .get_port          = udp_v6_get_port,
+       .obj_size          = sizeof(struct udp6_sock),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_udpv6_setsockopt,
+       .compat_getsockopt = compat_udpv6_getsockopt,
+#endif
 };
 
 static struct inet_protosw udpv6_protosw = {
index 8cfc58b..08f9abb 100644 (file)
@@ -31,6 +31,7 @@
 #include <net/protocol.h>
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
+#include <linux/mutex.h>
 
 #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG
 # define X6TDEBUG      3
@@ -357,19 +358,19 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *dec
 }
 
 static struct xfrm6_tunnel *xfrm6_tunnel_handler;
-static DECLARE_MUTEX(xfrm6_tunnel_sem);
+static DEFINE_MUTEX(xfrm6_tunnel_mutex);
 
 int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
 {
        int ret;
 
-       down(&xfrm6_tunnel_sem);
+       mutex_lock(&xfrm6_tunnel_mutex);
        ret = 0;
        if (xfrm6_tunnel_handler != NULL)
                ret = -EINVAL;
        if (!ret)
                xfrm6_tunnel_handler = handler;
-       up(&xfrm6_tunnel_sem);
+       mutex_unlock(&xfrm6_tunnel_mutex);
 
        return ret;
 }
@@ -380,13 +381,13 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
 {
        int ret;
 
-       down(&xfrm6_tunnel_sem);
+       mutex_lock(&xfrm6_tunnel_mutex);
        ret = 0;
        if (xfrm6_tunnel_handler != handler)
                ret = -EINVAL;
        if (!ret)
                xfrm6_tunnel_handler = NULL;
-       up(&xfrm6_tunnel_sem);
+       mutex_unlock(&xfrm6_tunnel_mutex);
 
        synchronize_net();
 
index b2d4d1d..8595822 100644 (file)
@@ -2651,6 +2651,8 @@ static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
                return key_notify_sa(x, c);
        case XFRM_MSG_FLUSHSA:
                return key_notify_sa_flush(c);
+       case XFRM_MSG_NEWAE: /* not yet supported */
+               break;
        default:
                printk("pfkey: Unknown SA event %d\n", c->event);
                break;
@@ -3078,9 +3080,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
        if (!hdr)
                goto out;
 
-       down(&xfrm_cfg_sem);
+       mutex_lock(&xfrm_cfg_mutex);
        err = pfkey_process(sk, skb, hdr);
-       up(&xfrm_cfg_sem);
+       mutex_unlock(&xfrm_cfg_mutex);
 
 out:
        if (err && hdr && pfkey_error(hdr, err, sk) == 0)
index 8171c53..5a04db7 100644 (file)
@@ -54,7 +54,7 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout);
  *
  *     Return the next unused link number for a given sap.
  */
-static __inline__ u16 llc_ui_next_link_no(int sap)
+static inline u16 llc_ui_next_link_no(int sap)
 {
        return llc_ui_sap_link_no_max[sap]++;
 }
@@ -65,7 +65,7 @@ static __inline__ u16 llc_ui_next_link_no(int sap)
  *
  *     Given an ARP header type return the corresponding ethernet protocol.
  */
-static __inline__ u16 llc_proto_type(u16 arphrd)
+static inline u16 llc_proto_type(u16 arphrd)
 {
        return arphrd == ARPHRD_IEEE802_TR ?
                         htons(ETH_P_TR_802_2) : htons(ETH_P_802_2);
@@ -75,7 +75,7 @@ static __inline__ u16 llc_proto_type(u16 arphrd)
  *     llc_ui_addr_null - determines if a address structure is null
  *     @addr: Address to test if null.
  */
-static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr)
+static inline u8 llc_ui_addr_null(struct sockaddr_llc *addr)
 {
        return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr));
 }
@@ -89,8 +89,7 @@ static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr)
  *     operation the user would like to perform and the type of socket.
  *     Returns the correct llc header length.
  */
-static __inline__ u8 llc_ui_header_len(struct sock *sk,
-                                      struct sockaddr_llc *addr)
+static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
 {
        u8 rc = LLC_PDU_LEN_U;
 
@@ -138,7 +137,7 @@ static void llc_ui_sk_init(struct socket *sock, struct sock *sk)
 }
 
 static struct proto llc_proto = {
-       .name     = "DDP",
+       .name     = "LLC",
        .owner    = THIS_MODULE,
        .obj_size = sizeof(struct llc_sock),
 };
@@ -188,8 +187,10 @@ static int llc_ui_release(struct socket *sock)
                llc->laddr.lsap, llc->daddr.lsap);
        if (!llc_send_disc(sk))
                llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
-       if (!sock_flag(sk, SOCK_ZAPPED))
+       if (!sock_flag(sk, SOCK_ZAPPED)) {
+               llc_sap_put(llc->sap);
                llc_sap_remove_socket(llc->sap, sk);
+       }
        release_sock(sk);
        if (llc->dev)
                dev_put(llc->dev);
index 8169f24..860140c 100644 (file)
@@ -27,7 +27,6 @@
 #include <net/llc_pdu.h>
 #include <net/llc.h>
 
-#include "llc_output.h"
 
 static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb);
 static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb);
index ab0fcd3..bd242a4 100644 (file)
@@ -127,7 +127,6 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
                goto out;
        sap->laddr.lsap = lsap;
        sap->rcv_func   = func;
-       llc_sap_hold(sap);
        llc_add_sap(sap);
 out:
        write_unlock_bh(&llc_sap_list_lock);
index b4d55b6..b4e668e 100644 (file)
@@ -30,7 +30,8 @@
  *     Fills MAC header fields, depending on MAC type. Returns 0, If MAC type
  *     is a valid type and initialization completes correctly 1, otherwise.
  */
-int llc_mac_hdr_init(struct sk_buff *skb, unsigned char *sa, unsigned char *da)
+int llc_mac_hdr_init(struct sk_buff *skb,
+                    const unsigned char *sa, const unsigned char *da)
 {
        int rc = 0;
 
diff --git a/net/llc/llc_output.h b/net/llc/llc_output.h
deleted file mode 100644 (file)
index 179edf7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef LLC_OUTPUT_H
-#define LLC_OUTPUT_H
-/*
- * Copyright (c) 1997 by Procom Technology, Inc.
- *              2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- * This program can be redistributed or modified under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation.
- * This program is distributed without any warranty or implied warranty
- * of merchantability or fitness for a particular purpose.
- *
- * See the GNU General Public License version 2 for more details.
- */
-
-struct sk_buff;
-
-int llc_mac_hdr_init(struct sk_buff *skb, unsigned char *sa, unsigned char *da);
-
-#endif /* LLC_OUTPUT_H */
index bb3580f..ac3d93b 100644 (file)
@@ -24,7 +24,7 @@
 #include <net/llc_s_ac.h>
 #include <net/llc_s_ev.h>
 #include <net/llc_sap.h>
-#include "llc_output.h"
+
 
 /**
  *     llc_sap_action_unit_data_ind - forward UI PDU to network layer
index a8e5544..1740278 100644 (file)
@@ -279,6 +279,16 @@ config NETFILTER_XT_MATCH_MARK
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_POLICY
+       tristate 'IPsec "policy" match support'
+       depends on NETFILTER_XTABLES && XFRM
+       help
+         Policy matching allows you to match packets based on the
+         IPsec policy that was used during decapsulation/will
+         be used during encapsulation.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_PHYSDEV
        tristate '"physdev" match support'
        depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
index 746172e..9558727 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
index d622ddf..f649823 100644 (file)
@@ -3,7 +3,7 @@
    extension. */
 
 /* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
  * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,9 @@
  *     - generalize L3 protocol denendent part.
  * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
  *     - add support various size of conntrack structures.
+ * 26 Jan 2006: Harald Welte <laforge@netfilter.org>
+ *     - restructure nf_conn (introduce nf_conn_help)
+ *     - redesign 'features' how they were originally intended
  *
  * Derived from net/ipv4/netfilter/ip_conntrack_core.c
  */
@@ -55,7 +58,7 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
-#define NF_CONNTRACK_VERSION   "0.4.1"
+#define NF_CONNTRACK_VERSION   "0.5.0"
 
 #if 0
 #define DEBUGP printk
@@ -182,7 +185,7 @@ static struct {
 DEFINE_RWLOCK(nf_ct_cache_lock);
 
 /* This avoids calling kmem_cache_create() with same name simultaneously */
-DECLARE_MUTEX(nf_ct_cache_mutex);
+static DEFINE_MUTEX(nf_ct_cache_mutex);
 
 extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
 struct nf_conntrack_protocol *
@@ -259,21 +262,8 @@ static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple)
                                nf_conntrack_hash_rnd);
 }
 
-/* Initialize "struct nf_conn" which has spaces for helper */
-static int
-init_conntrack_for_helper(struct nf_conn *conntrack, u_int32_t features)
-{
-
-       conntrack->help = (union nf_conntrack_help *)
-               (((unsigned long)conntrack->data
-                 + (__alignof__(union nf_conntrack_help) - 1))
-                & (~((unsigned long)(__alignof__(union nf_conntrack_help) -1))));
-       return 0;
-}
-
 int nf_conntrack_register_cache(u_int32_t features, const char *name,
-                               size_t size,
-                               int (*init)(struct nf_conn *, u_int32_t))
+                               size_t size)
 {
        int ret = 0;
        char *cache_name;
@@ -288,7 +278,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name,
                return -EINVAL;
        }
 
-       down(&nf_ct_cache_mutex);
+       mutex_lock(&nf_ct_cache_mutex);
 
        write_lock_bh(&nf_ct_cache_lock);
        /* e.g: multiple helpers are loaded */
@@ -296,8 +286,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name,
                DEBUGP("nf_conntrack_register_cache: already resisterd.\n");
                if ((!strncmp(nf_ct_cache[features].name, name,
                              NF_CT_FEATURES_NAMELEN))
-                   && nf_ct_cache[features].size == size
-                   && nf_ct_cache[features].init_conntrack == init) {
+                   && nf_ct_cache[features].size == size) {
                        DEBUGP("nf_conntrack_register_cache: reusing.\n");
                        nf_ct_cache[features].use++;
                        ret = 0;
@@ -305,7 +294,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name,
                        ret = -EBUSY;
 
                write_unlock_bh(&nf_ct_cache_lock);
-               up(&nf_ct_cache_mutex);
+               mutex_unlock(&nf_ct_cache_mutex);
                return ret;
        }
        write_unlock_bh(&nf_ct_cache_lock);
@@ -340,7 +329,6 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name,
        write_lock_bh(&nf_ct_cache_lock);
        nf_ct_cache[features].use = 1;
        nf_ct_cache[features].size = size;
-       nf_ct_cache[features].init_conntrack = init;
        nf_ct_cache[features].cachep = cachep;
        nf_ct_cache[features].name = cache_name;
        write_unlock_bh(&nf_ct_cache_lock);
@@ -350,7 +338,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name,
 out_free_name:
        kfree(cache_name);
 out_up_mutex:
-       up(&nf_ct_cache_mutex);
+       mutex_unlock(&nf_ct_cache_mutex);
        return ret;
 }
 
@@ -365,19 +353,18 @@ void nf_conntrack_unregister_cache(u_int32_t features)
         * slab cache.
         */
        DEBUGP("nf_conntrack_unregister_cache: 0x%04x\n", features);
-       down(&nf_ct_cache_mutex);
+       mutex_lock(&nf_ct_cache_mutex);
 
        write_lock_bh(&nf_ct_cache_lock);
        if (--nf_ct_cache[features].use > 0) {
                write_unlock_bh(&nf_ct_cache_lock);
-               up(&nf_ct_cache_mutex);
+               mutex_unlock(&nf_ct_cache_mutex);
                return;
        }
        cachep = nf_ct_cache[features].cachep;
        name = nf_ct_cache[features].name;
        nf_ct_cache[features].cachep = NULL;
        nf_ct_cache[features].name = NULL;
-       nf_ct_cache[features].init_conntrack = NULL;
        nf_ct_cache[features].size = 0;
        write_unlock_bh(&nf_ct_cache_lock);
 
@@ -386,7 +373,7 @@ void nf_conntrack_unregister_cache(u_int32_t features)
        kmem_cache_destroy(cachep);
        kfree(name);
 
-       up(&nf_ct_cache_mutex);
+       mutex_unlock(&nf_ct_cache_mutex);
 }
 
 int
@@ -432,11 +419,15 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
 /* nf_conntrack_expect helper functions */
 void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
 {
+       struct nf_conn_help *master_help = nfct_help(exp->master);
+
+       NF_CT_ASSERT(master_help);
        ASSERT_WRITE_LOCK(&nf_conntrack_lock);
        NF_CT_ASSERT(!timer_pending(&exp->timeout));
+
        list_del(&exp->list);
        NF_CT_STAT_INC(expect_delete);
-       exp->master->expecting--;
+       master_help->expecting--;
        nf_conntrack_expect_put(exp);
 }
 
@@ -508,9 +499,10 @@ find_expectation(const struct nf_conntrack_tuple *tuple)
 void nf_ct_remove_expectations(struct nf_conn *ct)
 {
        struct nf_conntrack_expect *i, *tmp;
+       struct nf_conn_help *help = nfct_help(ct);
 
        /* Optimization: most connection never expect any others. */
-       if (ct->expecting == 0)
+       if (!help || help->expecting == 0)
                return;
 
        list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) {
@@ -713,6 +705,7 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
                          conntrack_tuple_cmp,
                          struct nf_conntrack_tuple_hash *,
                          &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
+               struct nf_conn_help *help;
                /* Remove from unconfirmed list */
                list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
 
@@ -726,7 +719,8 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
                set_bit(IPS_CONFIRMED_BIT, &ct->status);
                NF_CT_STAT_INC(insert);
                write_unlock_bh(&nf_conntrack_lock);
-               if (ct->helper)
+               help = nfct_help(ct);
+               if (help && help->helper)
                        nf_conntrack_event_cache(IPCT_HELPER, *pskb);
 #ifdef CONFIG_NF_NAT_NEEDED
                if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
@@ -842,8 +836,9 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
 {
        struct nf_conn *conntrack = NULL;
        u_int32_t features = 0;
+       struct nf_conntrack_helper *helper;
 
-       if (!nf_conntrack_hash_rnd_initted) {
+       if (unlikely(!nf_conntrack_hash_rnd_initted)) {
                get_random_bytes(&nf_conntrack_hash_rnd, 4);
                nf_conntrack_hash_rnd_initted = 1;
        }
@@ -863,8 +858,11 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
 
        /*  find features needed by this conntrack. */
        features = l3proto->get_features(orig);
+
+       /* FIXME: protect helper list per RCU */
        read_lock_bh(&nf_conntrack_lock);
-       if (__nf_ct_helper_find(repl) != NULL)
+       helper = __nf_ct_helper_find(repl);
+       if (helper)
                features |= NF_CT_F_HELP;
        read_unlock_bh(&nf_conntrack_lock);
 
@@ -872,7 +870,7 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
 
        read_lock_bh(&nf_ct_cache_lock);
 
-       if (!nf_ct_cache[features].use) {
+       if (unlikely(!nf_ct_cache[features].use)) {
                DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n",
                        features);
                goto out;
@@ -886,12 +884,10 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
 
        memset(conntrack, 0, nf_ct_cache[features].size);
        conntrack->features = features;
-       if (nf_ct_cache[features].init_conntrack &&
-           nf_ct_cache[features].init_conntrack(conntrack, features) < 0) {
-               DEBUGP("nf_conntrack_alloc: failed to init\n");
-               kmem_cache_free(nf_ct_cache[features].cachep, conntrack);
-               conntrack = NULL;
-               goto out;
+       if (helper) {
+               struct nf_conn_help *help = nfct_help(conntrack);
+               NF_CT_ASSERT(help);
+               help->helper = helper;
        }
 
        atomic_set(&conntrack->ct_general.use, 1);
@@ -972,11 +968,8 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
 #endif
                nf_conntrack_get(&conntrack->master->ct_general);
                NF_CT_STAT_INC(expect_new);
-       } else {
-               conntrack->helper = __nf_ct_helper_find(&repl_tuple);
-
+       } else
                NF_CT_STAT_INC(new);
-        }
 
        /* Overload tuple linked list to put us in unconfirmed list. */
        list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed);
@@ -1206,14 +1199,16 @@ void nf_conntrack_expect_put(struct nf_conntrack_expect *exp)
 
 static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
 {
+       struct nf_conn_help *master_help = nfct_help(exp->master);
+
        atomic_inc(&exp->use);
-       exp->master->expecting++;
+       master_help->expecting++;
        list_add(&exp->list, &nf_conntrack_expect_list);
 
        init_timer(&exp->timeout);
        exp->timeout.data = (unsigned long)exp;
        exp->timeout.function = expectation_timed_out;
-       exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ;
+       exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
        add_timer(&exp->timeout);
 
        exp->id = ++nf_conntrack_expect_next_id;
@@ -1239,10 +1234,12 @@ static void evict_oldest_expect(struct nf_conn *master)
 
 static inline int refresh_timer(struct nf_conntrack_expect *i)
 {
+       struct nf_conn_help *master_help = nfct_help(i->master);
+
        if (!del_timer(&i->timeout))
                return 0;
 
-       i->timeout.expires = jiffies + i->master->helper->timeout*HZ;
+       i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
        add_timer(&i->timeout);
        return 1;
 }
@@ -1251,8 +1248,11 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
 {
        struct nf_conntrack_expect *i;
        struct nf_conn *master = expect->master;
+       struct nf_conn_help *master_help = nfct_help(master);
        int ret;
 
+       NF_CT_ASSERT(master_help);
+
        DEBUGP("nf_conntrack_expect_related %p\n", related_to);
        DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple);
        DEBUGP("mask:  "); NF_CT_DUMP_TUPLE(&expect->mask);
@@ -1271,8 +1271,8 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
                }
        }
        /* Will be over limit? */
-       if (master->helper->max_expected && 
-           master->expecting >= master->helper->max_expected)
+       if (master_help->helper->max_expected &&
+           master_help->expecting >= master_help->helper->max_expected)
                evict_oldest_expect(master);
 
        nf_conntrack_expect_insert(expect);
@@ -1283,24 +1283,6 @@ out:
        return ret;
 }
 
-/* Alter reply tuple (maybe alter helper).  This is for NAT, and is
-   implicitly racy: see __nf_conntrack_confirm */
-void nf_conntrack_alter_reply(struct nf_conn *conntrack,
-                             const struct nf_conntrack_tuple *newreply)
-{
-       write_lock_bh(&nf_conntrack_lock);
-       /* Should be unconfirmed, so not in hash table yet */
-       NF_CT_ASSERT(!nf_ct_is_confirmed(conntrack));
-
-       DEBUGP("Altering reply tuple of %p to ", conntrack);
-       NF_CT_DUMP_TUPLE(newreply);
-
-       conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-       if (!conntrack->master && conntrack->expecting == 0)
-               conntrack->helper = __nf_ct_helper_find(newreply);
-       write_unlock_bh(&nf_conntrack_lock);
-}
-
 int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 {
        int ret;
@@ -1308,9 +1290,8 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 
        ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help",
                                          sizeof(struct nf_conn)
-                                         + sizeof(union nf_conntrack_help)
-                                         + __alignof__(union nf_conntrack_help),
-                                         init_conntrack_for_helper);
+                                         + sizeof(struct nf_conn_help)
+                                         + __alignof__(struct nf_conn_help));
        if (ret < 0) {
                printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n");
                return ret;
@@ -1338,9 +1319,12 @@ __nf_conntrack_helper_find_byname(const char *name)
 static inline int unhelp(struct nf_conntrack_tuple_hash *i,
                         const struct nf_conntrack_helper *me)
 {
-       if (nf_ct_tuplehash_to_ctrack(i)->helper == me) {
-               nf_conntrack_event(IPCT_HELPER, nf_ct_tuplehash_to_ctrack(i));
-               nf_ct_tuplehash_to_ctrack(i)->helper = NULL;
+       struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
+       struct nf_conn_help *help = nfct_help(ct);
+
+       if (help && help->helper == me) {
+               nf_conntrack_event(IPCT_HELPER, ct);
+               help->helper = NULL;
        }
        return 0;
 }
@@ -1356,7 +1340,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
 
        /* Get rid of expectations */
        list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) {
-               if (exp->master->helper == me && del_timer(&exp->timeout)) {
+               struct nf_conn_help *help = nfct_help(exp->master);
+               if (help->helper == me && del_timer(&exp->timeout)) {
                        nf_ct_unlink_expect(exp);
                        nf_conntrack_expect_put(exp);
                }
@@ -1423,6 +1408,8 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
 
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_conntrack.h>
+#include <linux/mutex.h>
+
 
 /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be
  * in ip_conntrack_core, since we don't want the protocols to autoload
@@ -1697,7 +1684,7 @@ int __init nf_conntrack_init(void)
        }
 
        ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic",
-                                         sizeof(struct nf_conn), NULL);
+                                         sizeof(struct nf_conn));
        if (ret < 0) {
                printk(KERN_ERR "Unable to create nf_conn slab cache\n");
                goto err_free_hash;
index 6f210f3..cd191b0 100644 (file)
@@ -440,7 +440,7 @@ static int help(struct sk_buff **pskb,
        u32 seq;
        int dir = CTINFO2DIR(ctinfo);
        unsigned int matchlen, matchoff;
-       struct ip_ct_ftp_master *ct_ftp_info = &ct->help->ct_ftp_info;
+       struct ip_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info;
        struct nf_conntrack_expect *exp;
        struct nf_conntrack_man cmd = {};
 
index 9ff3463..5eadf00 100644 (file)
@@ -2,7 +2,7 @@
  * protocol helpers and general trouble making from userspace.
  *
  * (C) 2001 by Jay Schulist <jschlst@samba.org>
- * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
  * (C) 2003 by Patrick Mchardy <kaber@trash.net>
  * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
  *
@@ -44,7 +44,7 @@
 
 MODULE_LICENSE("GPL");
 
-static char __initdata version[] = "0.92";
+static char __initdata version[] = "0.93";
 
 #if 0
 #define DEBUGP printk
@@ -165,15 +165,16 @@ static inline int
 ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
 {
        struct nfattr *nest_helper;
+       const struct nf_conn_help *help = nfct_help(ct);
 
-       if (!ct->helper)
+       if (!help || !help->helper)
                return 0;
                
        nest_helper = NFA_NEST(skb, CTA_HELP);
-       NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name);
+       NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name);
 
-       if (ct->helper->to_nfattr)
-               ct->helper->to_nfattr(skb, ct);
+       if (help->helper->to_nfattr)
+               help->helper->to_nfattr(skb, ct);
 
        NFA_NEST_END(skb, nest_helper);
 
@@ -337,9 +338,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
                group = NFNLGRP_CONNTRACK_UPDATE;
        } else
                return NOTIFY_DONE;
-       
-  /* FIXME: Check if there are any listeners before, don't hurt performance */
-       
+
+       if (!nfnetlink_has_listeners(group))
+               return NOTIFY_DONE;
+
        skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
        if (!skb)
                return NOTIFY_DONE;
@@ -903,11 +905,17 @@ static inline int
 ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
 {
        struct nf_conntrack_helper *helper;
+       struct nf_conn_help *help = nfct_help(ct);
        char *helpname;
        int err;
 
        DEBUGP("entered %s\n", __FUNCTION__);
 
+       if (!help) {
+               /* FIXME: we need to reallocate and rehash */
+               return -EBUSY;
+       }
+
        /* don't change helper of sibling connections */
        if (ct->master)
                return -EINVAL;
@@ -924,18 +932,18 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
                        return -EINVAL;
        }
 
-       if (ct->helper) {
+       if (help->helper) {
                if (!helper) {
                        /* we had a helper before ... */
                        nf_ct_remove_expectations(ct);
-                       ct->helper = NULL;
+                       help->helper = NULL;
                } else {
                        /* need to zero data of old helper */
-                       memset(&ct->help, 0, sizeof(ct->help));
+                       memset(&help->help, 0, sizeof(help->help));
                }
        }
        
-       ct->helper = helper;
+       help->helper = helper;
 
        return 0;
 }
@@ -1050,14 +1058,9 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
                ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
 #endif
 
-       ct->helper = nf_ct_helper_find_get(rtuple);
-
        add_timer(&ct->timeout);
        nf_conntrack_hash_insert(ct);
 
-       if (ct->helper)
-               nf_ct_helper_put(ct->helper);
-
        DEBUGP("conntrack with id %u inserted\n", ct->id);
        return 0;
 
@@ -1417,7 +1420,8 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                }
                list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list,
                                         list) {
-                       if (exp->master->helper == h 
+                       struct nf_conn_help *m_help = nfct_help(exp->master);
+                       if (m_help->helper == h
                            && del_timer(&exp->timeout)) {
                                nf_ct_unlink_expect(exp);
                                nf_conntrack_expect_put(exp);
@@ -1452,6 +1456,7 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
        struct nf_conntrack_tuple_hash *h = NULL;
        struct nf_conntrack_expect *exp;
        struct nf_conn *ct;
+       struct nf_conn_help *help;
        int err = 0;
 
        DEBUGP("entered %s\n", __FUNCTION__);
@@ -1472,8 +1477,9 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
        if (!h)
                return -ENOENT;
        ct = nf_ct_tuplehash_to_ctrack(h);
+       help = nfct_help(ct);
 
-       if (!ct->helper) {
+       if (!help || !help->helper) {
                /* such conntrack hasn't got any helper, abort */
                err = -EINVAL;
                goto out;
index 617599a..290d5a0 100644 (file)
@@ -839,7 +839,6 @@ EXPORT_SYMBOL(nf_conntrack_l3proto_unregister);
 EXPORT_SYMBOL(nf_conntrack_protocol_register);
 EXPORT_SYMBOL(nf_conntrack_protocol_unregister);
 EXPORT_SYMBOL(nf_ct_invert_tuplepr);
-EXPORT_SYMBOL(nf_conntrack_alter_reply);
 EXPORT_SYMBOL(nf_conntrack_destroyed);
 EXPORT_SYMBOL(need_conntrack);
 EXPORT_SYMBOL(nf_conntrack_helper_register);
index 61a833a..0a63d7d 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 
 #include "nf_internals.h"
@@ -11,7 +12,7 @@
 /* Sockopts only registered and called from user context, so
    net locking would be overkill.  Also, [gs]etsockopt calls may
    sleep. */
-static DECLARE_MUTEX(nf_sockopt_mutex);
+static DEFINE_MUTEX(nf_sockopt_mutex);
 static LIST_HEAD(nf_sockopts);
 
 /* Do exclusive ranges overlap? */
@@ -26,7 +27,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg)
        struct list_head *i;
        int ret = 0;
 
-       if (down_interruptible(&nf_sockopt_mutex) != 0)
+       if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
        list_for_each(i, &nf_sockopts) {
@@ -48,7 +49,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg)
 
        list_add(&reg->list, &nf_sockopts);
 out:
-       up(&nf_sockopt_mutex);
+       mutex_unlock(&nf_sockopt_mutex);
        return ret;
 }
 EXPORT_SYMBOL(nf_register_sockopt);
@@ -57,18 +58,18 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
 {
        /* No point being interruptible: we're probably in cleanup_module() */
  restart:
-       down(&nf_sockopt_mutex);
+       mutex_lock(&nf_sockopt_mutex);
        if (reg->use != 0) {
                /* To be woken by nf_sockopt call... */
                /* FIXME: Stuart Young's name appears gratuitously. */
                set_current_state(TASK_UNINTERRUPTIBLE);
                reg->cleanup_task = current;
-               up(&nf_sockopt_mutex);
+               mutex_unlock(&nf_sockopt_mutex);
                schedule();
                goto restart;
        }
        list_del(&reg->list);
-       up(&nf_sockopt_mutex);
+       mutex_unlock(&nf_sockopt_mutex);
 }
 EXPORT_SYMBOL(nf_unregister_sockopt);
 
@@ -80,7 +81,7 @@ static int nf_sockopt(struct sock *sk, int pf, int val,
        struct nf_sockopt_ops *ops;
        int ret;
 
-       if (down_interruptible(&nf_sockopt_mutex) != 0)
+       if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
        list_for_each(i, &nf_sockopts) {
@@ -90,7 +91,7 @@ static int nf_sockopt(struct sock *sk, int pf, int val,
                                if (val >= ops->get_optmin
                                    && val < ops->get_optmax) {
                                        ops->use++;
-                                       up(&nf_sockopt_mutex);
+                                       mutex_unlock(&nf_sockopt_mutex);
                                        ret = ops->get(sk, val, opt, len);
                                        goto out;
                                }
@@ -98,22 +99,22 @@ static int nf_sockopt(struct sock *sk, int pf, int val,
                                if (val >= ops->set_optmin
                                    && val < ops->set_optmax) {
                                        ops->use++;
-                                       up(&nf_sockopt_mutex);
+                                       mutex_unlock(&nf_sockopt_mutex);
                                        ret = ops->set(sk, val, opt, *len);
                                        goto out;
                                }
                        }
                }
        }
-       up(&nf_sockopt_mutex);
+       mutex_unlock(&nf_sockopt_mutex);
        return -ENOPROTOOPT;
        
  out:
-       down(&nf_sockopt_mutex);
+       mutex_lock(&nf_sockopt_mutex);
        ops->use--;
        if (ops->cleanup_task)
                wake_up_process(ops->cleanup_task);
-       up(&nf_sockopt_mutex);
+       mutex_unlock(&nf_sockopt_mutex);
        return ret;
 }
 
@@ -130,3 +131,72 @@ int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len)
 }
 EXPORT_SYMBOL(nf_getsockopt);
 
+#ifdef CONFIG_COMPAT
+static int compat_nf_sockopt(struct sock *sk, int pf, int val,
+                            char __user *opt, int *len, int get)
+{
+       struct list_head *i;
+       struct nf_sockopt_ops *ops;
+       int ret;
+
+       if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
+               return -EINTR;
+
+       list_for_each(i, &nf_sockopts) {
+               ops = (struct nf_sockopt_ops *)i;
+               if (ops->pf == pf) {
+                       if (get) {
+                               if (val >= ops->get_optmin
+                                   && val < ops->get_optmax) {
+                                       ops->use++;
+                                       mutex_unlock(&nf_sockopt_mutex);
+                                       if (ops->compat_get)
+                                               ret = ops->compat_get(sk,
+                                                       val, opt, len);
+                                       else
+                                               ret = ops->get(sk,
+                                                       val, opt, len);
+                                       goto out;
+                               }
+                       } else {
+                               if (val >= ops->set_optmin
+                                   && val < ops->set_optmax) {
+                                       ops->use++;
+                                       mutex_unlock(&nf_sockopt_mutex);
+                                       if (ops->compat_set)
+                                               ret = ops->compat_set(sk,
+                                                       val, opt, *len);
+                                       else
+                                               ret = ops->set(sk,
+                                                       val, opt, *len);
+                                       goto out;
+                               }
+                       }
+               }
+       }
+       mutex_unlock(&nf_sockopt_mutex);
+       return -ENOPROTOOPT;
+
+ out:
+       mutex_lock(&nf_sockopt_mutex);
+       ops->use--;
+       if (ops->cleanup_task)
+               wake_up_process(ops->cleanup_task);
+       mutex_unlock(&nf_sockopt_mutex);
+       return ret;
+}
+
+int compat_nf_setsockopt(struct sock *sk, int pf,
+               int val, char __user *opt, int len)
+{
+       return compat_nf_sockopt(sk, pf, val, opt, &len, 0);
+}
+EXPORT_SYMBOL(compat_nf_setsockopt);
+
+int compat_nf_getsockopt(struct sock *sk, int pf,
+               int val, char __user *opt, int *len)
+{
+       return compat_nf_sockopt(sk, pf, val, opt, len, 1);
+}
+EXPORT_SYMBOL(compat_nf_getsockopt);
+#endif
index f6063e8..b88e82a 100644 (file)
@@ -191,6 +191,12 @@ nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
         return 0;
 }
 
+int nfnetlink_has_listeners(unsigned int group)
+{
+       return netlink_has_listeners(nfnl, group);
+}
+EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
+
 int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
 {
        gfp_t allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
index 3b3c781..54cbbaa 100644 (file)
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
+ * 2006-01-26 Harald Welte <laforge@netfilter.org>
+ *     - Add optional local and global sequence number to detect lost
+ *       events from userspace
+ *
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -68,11 +72,14 @@ struct nfulnl_instance {
        unsigned int nlbufsiz;          /* netlink buffer allocation size */
        unsigned int qthreshold;        /* threshold of the queue */
        u_int32_t copy_range;
+       u_int32_t seq;                  /* instance-local sequential counter */
        u_int16_t group_num;            /* number of this queue */
+       u_int16_t flags;
        u_int8_t copy_mode;     
 };
 
 static DEFINE_RWLOCK(instances_lock);
+static atomic_t global_seq;
 
 #define INSTANCE_BUCKETS       16
 static struct hlist_head instance_table[INSTANCE_BUCKETS];
@@ -310,6 +317,16 @@ nfulnl_set_qthresh(struct nfulnl_instance *inst, u_int32_t qthresh)
        return 0;
 }
 
+static int
+nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags)
+{
+       spin_lock_bh(&inst->lock);
+       inst->flags = ntohs(flags);
+       spin_unlock_bh(&inst->lock);
+
+       return 0;
+}
+
 static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size, 
                                        unsigned int pkt_size)
 {
@@ -377,6 +394,8 @@ static void nfulnl_timer(unsigned long data)
        spin_unlock_bh(&inst->lock);
 }
 
+/* This is an inline function, we don't really care about a long
+ * list of arguments */
 static inline int 
 __build_packet_message(struct nfulnl_instance *inst,
                        const struct sk_buff *skb, 
@@ -515,6 +534,17 @@ __build_packet_message(struct nfulnl_instance *inst,
                        read_unlock_bh(&skb->sk->sk_callback_lock);
        }
 
+       /* local sequence number */
+       if (inst->flags & NFULNL_CFG_F_SEQ) {
+               tmp_uint = htonl(inst->seq++);
+               NFA_PUT(inst->skb, NFULA_SEQ, sizeof(tmp_uint), &tmp_uint);
+       }
+       /* global sequence number */
+       if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) {
+               tmp_uint = atomic_inc_return(&global_seq);
+               NFA_PUT(inst->skb, NFULA_SEQ_GLOBAL, sizeof(tmp_uint), &tmp_uint);
+       }
+
        if (data_len) {
                struct nfattr *nfa;
                int size = NFA_LENGTH(data_len);
@@ -607,6 +637,11 @@ nfulnl_log_packet(unsigned int pf,
 
        spin_lock_bh(&inst->lock);
 
+       if (inst->flags & NFULNL_CFG_F_SEQ)
+               size += NFA_SPACE(sizeof(u_int32_t));
+       if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL)
+               size += NFA_SPACE(sizeof(u_int32_t));
+
        qthreshold = inst->qthreshold;
        /* per-rule qthreshold overrides per-instance */
        if (qthreshold > li->u.ulog.qthreshold)
@@ -736,10 +771,14 @@ static const int nfula_min[NFULA_MAX] = {
        [NFULA_TIMESTAMP-1]     = sizeof(struct nfulnl_msg_packet_timestamp),
        [NFULA_IFINDEX_INDEV-1] = sizeof(u_int32_t),
        [NFULA_IFINDEX_OUTDEV-1]= sizeof(u_int32_t),
+       [NFULA_IFINDEX_PHYSINDEV-1]     = sizeof(u_int32_t),
+       [NFULA_IFINDEX_PHYSOUTDEV-1]    = sizeof(u_int32_t),
        [NFULA_HWADDR-1]        = sizeof(struct nfulnl_msg_packet_hw),
        [NFULA_PAYLOAD-1]       = 0,
        [NFULA_PREFIX-1]        = 0,
        [NFULA_UID-1]           = sizeof(u_int32_t),
+       [NFULA_SEQ-1]           = sizeof(u_int32_t),
+       [NFULA_SEQ_GLOBAL-1]    = sizeof(u_int32_t),
 };
 
 static const int nfula_cfg_min[NFULA_CFG_MAX] = {
@@ -748,6 +787,7 @@ static const int nfula_cfg_min[NFULA_CFG_MAX] = {
        [NFULA_CFG_TIMEOUT-1]   = sizeof(u_int32_t),
        [NFULA_CFG_QTHRESH-1]   = sizeof(u_int32_t),
        [NFULA_CFG_NLBUFSIZ-1]  = sizeof(u_int32_t),
+       [NFULA_CFG_FLAGS-1]     = sizeof(u_int16_t),
 };
 
 static int
@@ -859,6 +899,12 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
                nfulnl_set_qthresh(inst, ntohl(qthresh));
        }
 
+       if (nfula[NFULA_CFG_FLAGS-1]) {
+               u_int16_t flags =
+                       *(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]);
+               nfulnl_set_flags(inst, ntohl(flags));
+       }
+
 out_put:
        instance_put(inst);
        return ret;
index d7817af..750b928 100644 (file)
@@ -52,6 +52,12 @@ enum {
        MATCH,
 };
 
+static const char *xt_prefix[NPROTO] = {
+       [AF_INET]       = "ip",
+       [AF_INET6]      = "ip6",
+       [NF_ARP]        = "arp",
+};
+
 /* Registration hooks for targets. */
 int
 xt_register_target(int af, struct xt_target *target)
@@ -158,18 +164,12 @@ struct xt_target *xt_find_target(int af, const char *name, u8 revision)
 }
 EXPORT_SYMBOL(xt_find_target);
 
-static const char *xt_prefix[NPROTO] = {
-       [AF_INET]       = "ipt_%s",
-       [AF_INET6]      = "ip6t_%s",
-       [NF_ARP]        = "arpt_%s",
-};
-
 struct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
 {
        struct xt_target *target;
 
        target = try_then_request_module(xt_find_target(af, name, revision),
-                                        xt_prefix[af], name);
+                                        "%st_%s", xt_prefix[af], name);
        if (IS_ERR(target) || !target)
                return NULL;
        return target;
@@ -237,6 +237,64 @@ int xt_find_revision(int af, const char *name, u8 revision, int target,
 }
 EXPORT_SYMBOL_GPL(xt_find_revision);
 
+int xt_check_match(const struct xt_match *match, unsigned short family,
+                   unsigned int size, const char *table, unsigned int hook_mask,
+                  unsigned short proto, int inv_proto)
+{
+       if (XT_ALIGN(match->matchsize) != size) {
+               printk("%s_tables: %s match: invalid size %Zu != %u\n",
+                      xt_prefix[family], match->name,
+                      XT_ALIGN(match->matchsize), size);
+               return -EINVAL;
+       }
+       if (match->table && strcmp(match->table, table)) {
+               printk("%s_tables: %s match: only valid in %s table, not %s\n",
+                      xt_prefix[family], match->name, match->table, table);
+               return -EINVAL;
+       }
+       if (match->hooks && (hook_mask & ~match->hooks) != 0) {
+               printk("%s_tables: %s match: bad hook_mask %u\n",
+                      xt_prefix[family], match->name, hook_mask);
+               return -EINVAL;
+       }
+       if (match->proto && (match->proto != proto || inv_proto)) {
+               printk("%s_tables: %s match: only valid for protocol %u\n",
+                      xt_prefix[family], match->name, match->proto);
+               return -EINVAL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xt_check_match);
+
+int xt_check_target(const struct xt_target *target, unsigned short family,
+                   unsigned int size, const char *table, unsigned int hook_mask,
+                   unsigned short proto, int inv_proto)
+{
+       if (XT_ALIGN(target->targetsize) != size) {
+               printk("%s_tables: %s target: invalid size %Zu != %u\n",
+                      xt_prefix[family], target->name,
+                      XT_ALIGN(target->targetsize), size);
+               return -EINVAL;
+       }
+       if (target->table && strcmp(target->table, table)) {
+               printk("%s_tables: %s target: only valid in %s table, not %s\n",
+                      xt_prefix[family], target->name, target->table, table);
+               return -EINVAL;
+       }
+       if (target->hooks && (hook_mask & ~target->hooks) != 0) {
+               printk("%s_tables: %s target: bad hook_mask %u\n",
+                      xt_prefix[family], target->name, hook_mask);
+               return -EINVAL;
+       }
+       if (target->proto && (target->proto != proto || inv_proto)) {
+               printk("%s_tables: %s target: only valid for protocol %u\n",
+                      xt_prefix[family], target->name, target->proto);
+               return -EINVAL;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xt_check_target);
+
 struct xt_table_info *xt_alloc_table_info(unsigned int size)
 {
        struct xt_table_info *newinfo;
index 78ee266..3224ed8 100644 (file)
@@ -28,6 +28,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -39,47 +40,22 @@ target(struct sk_buff **pskb,
        return XT_CONTINUE;
 }
 
-static int
-checkentry(const char *tablename,
-           const void *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-       if (targinfosize != XT_ALIGN(sizeof(struct xt_classify_target_info))){
-               printk(KERN_ERR "CLASSIFY: invalid size (%u != %Zu).\n",
-                      targinfosize,
-                      XT_ALIGN(sizeof(struct xt_classify_target_info)));
-               return 0;
-       }
-       
-       if (hook_mask & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
-                         (1 << NF_IP_POST_ROUTING))) {
-               printk(KERN_ERR "CLASSIFY: only valid in LOCAL_OUT, FORWARD "
-                               "and POST_ROUTING.\n");
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_ERR "CLASSIFY: can only be called from "
-                               "\"mangle\" table, not \"%s\".\n",
-                               tablename);
-               return 0;
-       }
-
-       return 1;
-}
-
 static struct xt_target classify_reg = { 
        .name           = "CLASSIFY", 
        .target         = target,
-       .checkentry     = checkentry,
+       .targetsize     = sizeof(struct xt_classify_target_info),
+       .table          = "mangle",
+       .hooks          = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
+                         (1 << NF_IP_POST_ROUTING),
        .me             = THIS_MODULE,
 };
 static struct xt_target classify6_reg = { 
        .name           = "CLASSIFY", 
        .target         = target,
-       .checkentry     = checkentry,
+       .targetsize     = sizeof(struct xt_classify_target_info),
+       .table          = "mangle",
+       .hooks          = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
+                         (1 << NF_IP_POST_ROUTING),
        .me             = THIS_MODULE,
 };
 
index 22506e3..df2486a 100644 (file)
@@ -37,6 +37,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -74,17 +75,12 @@ target(struct sk_buff **pskb,
 static int
 checkentry(const char *tablename,
           const void *entry,
+          const struct xt_target *target,
           void *targinfo,
           unsigned int targinfosize,
           unsigned int hook_mask)
 {
        struct xt_connmark_target_info *matchinfo = targinfo;
-       if (targinfosize != XT_ALIGN(sizeof(struct xt_connmark_target_info))) {
-               printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      XT_ALIGN(sizeof(struct xt_connmark_target_info)));
-               return 0;
-       }
 
        if (matchinfo->mode == XT_CONNMARK_RESTORE) {
            if (strcmp(tablename, "mangle") != 0) {
@@ -102,16 +98,19 @@ checkentry(const char *tablename,
 }
 
 static struct xt_target connmark_reg = {
-       .name = "CONNMARK",
-       .target = &target,
-       .checkentry = &checkentry,
-       .me = THIS_MODULE
+       .name           = "CONNMARK",
+       .target         = target,
+       .targetsize     = sizeof(struct xt_connmark_target_info),
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
 };
+
 static struct xt_target connmark6_reg = {
-       .name = "CONNMARK",
-       .target = &target,
-       .checkentry = &checkentry,
-       .me = THIS_MODULE
+       .name           = "CONNMARK",
+       .target         = target,
+       .targetsize     = sizeof(struct xt_connmark_target_info),
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
 };
 
 static int __init init(void)
index 0c11ee9..dcb5266 100644 (file)
@@ -26,6 +26,7 @@ target_v0(struct sk_buff **pskb,
          const struct net_device *in,
          const struct net_device *out,
          unsigned int hooknum,
+         const struct xt_target *target,
          const void *targinfo,
          void *userinfo)
 {
@@ -42,6 +43,7 @@ target_v1(struct sk_buff **pskb,
          const struct net_device *in,
          const struct net_device *out,
          unsigned int hooknum,
+         const struct xt_target *target,
          const void *targinfo,
          void *userinfo)
 {
@@ -72,53 +74,30 @@ target_v1(struct sk_buff **pskb,
 static int
 checkentry_v0(const char *tablename,
              const void *entry,
+             const struct xt_target *target,
              void *targinfo,
              unsigned int targinfosize,
              unsigned int hook_mask)
 {
        struct xt_mark_target_info *markinfo = targinfo;
 
-       if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info))) {
-               printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      XT_ALIGN(sizeof(struct xt_mark_target_info)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
        if (markinfo->mark > 0xffffffff) {
                printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
                return 0;
        }
-
        return 1;
 }
 
 static int
 checkentry_v1(const char *tablename,
              const void *entry,
+             const struct xt_target *target,
              void *targinfo,
              unsigned int targinfosize,
              unsigned int hook_mask)
 {
        struct xt_mark_target_info_v1 *markinfo = targinfo;
 
-       if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info_v1))){
-               printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      XT_ALIGN(sizeof(struct xt_mark_target_info_v1)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
        if (markinfo->mode != XT_MARK_SET
            && markinfo->mode != XT_MARK_AND
            && markinfo->mode != XT_MARK_OR) {
@@ -126,18 +105,18 @@ checkentry_v1(const char *tablename,
                       markinfo->mode);
                return 0;
        }
-
        if (markinfo->mark > 0xffffffff) {
                printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
                return 0;
        }
-
        return 1;
 }
 
 static struct xt_target ipt_mark_reg_v0 = {
        .name           = "MARK",
        .target         = target_v0,
+       .targetsize     = sizeof(struct xt_mark_target_info),
+       .table          = "mangle",
        .checkentry     = checkentry_v0,
        .me             = THIS_MODULE,
        .revision       = 0,
@@ -146,6 +125,8 @@ static struct xt_target ipt_mark_reg_v0 = {
 static struct xt_target ipt_mark_reg_v1 = {
        .name           = "MARK",
        .target         = target_v1,
+       .targetsize     = sizeof(struct xt_mark_target_info_v1),
+       .table          = "mangle",
        .checkentry     = checkentry_v1,
        .me             = THIS_MODULE,
        .revision       = 1,
@@ -154,6 +135,8 @@ static struct xt_target ipt_mark_reg_v1 = {
 static struct xt_target ip6t_mark_reg_v0 = {
        .name           = "MARK",
        .target         = target_v0,
+       .targetsize     = sizeof(struct xt_mark_target_info),
+       .table          = "mangle",
        .checkentry     = checkentry_v0,
        .me             = THIS_MODULE,
        .revision       = 0,
index 8b76b6f..39a963e 100644 (file)
@@ -28,6 +28,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -36,41 +37,24 @@ target(struct sk_buff **pskb,
        return NF_QUEUE_NR(tinfo->queuenum);
 }
 
-static int
-checkentry(const char *tablename,
-          const void *entry,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-       if (targinfosize != XT_ALIGN(sizeof(struct xt_NFQ_info))) {
-               printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      XT_ALIGN(sizeof(struct xt_NFQ_info)));
-               return 0;
-       }
-
-       return 1;
-}
-
 static struct xt_target ipt_NFQ_reg = {
        .name           = "NFQUEUE",
        .target         = target,
-       .checkentry     = checkentry,
+       .targetsize     = sizeof(struct xt_NFQ_info),
        .me             = THIS_MODULE,
 };
 
 static struct xt_target ip6t_NFQ_reg = {
        .name           = "NFQUEUE",
        .target         = target,
-       .checkentry     = checkentry,
+       .targetsize     = sizeof(struct xt_NFQ_info),
        .me             = THIS_MODULE,
 };
 
 static struct xt_target arpt_NFQ_reg = {
        .name           = "NFQUEUE",
        .target         = target,
-       .checkentry     = checkentry,
+       .targetsize     = sizeof(struct xt_NFQ_info),
        .me             = THIS_MODULE,
 };
 
index 24d477a..b8634e3 100644 (file)
@@ -15,6 +15,7 @@ target(struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        unsigned int hooknum,
+       const struct xt_target *target,
        const void *targinfo,
        void *userinfo)
 {
@@ -33,38 +34,20 @@ target(struct sk_buff **pskb,
        return XT_CONTINUE;
 }
 
-static int
-checkentry(const char *tablename,
-          const void *entry,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-       if (targinfosize != 0) {
-               printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
-                      targinfosize);
-               return 0;
-       }
-
-       if (strcmp(tablename, "raw") != 0) {
-               printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct xt_target notrack_reg = { 
-       .name = "NOTRACK", 
-       .target = target, 
-       .checkentry = checkentry,
-       .me = THIS_MODULE,
+static struct xt_target notrack_reg = {
+       .name           = "NOTRACK",
+       .target         = target,
+       .targetsize     = 0,
+       .table          = "raw",
+       .me             = THIS_MODULE,
 };
-static struct xt_target notrack6_reg = { 
-       .name = "NOTRACK", 
-       .target = target, 
-       .checkentry = checkentry,
-       .me = THIS_MODULE,
+
+static struct xt_target notrack6_reg = {
+       .name           = "NOTRACK",
+       .target         = target,
+       .targetsize     = 0,
+       .table          = "raw",
+       .me             = THIS_MODULE,
 };
 
 static int __init init(void)
index 4ba6fd6..03d9d74 100644 (file)
@@ -19,6 +19,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protooff,
@@ -28,30 +29,17 @@ match(const struct sk_buff *skb,
        return 1;
 }
 
-static int
-checkentry(const char *tablename,
-           const void *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       /* Check the size */
-       if (matchsize != XT_ALIGN(sizeof(struct xt_comment_info)))
-               return 0;
-       return 1;
-}
-
 static struct xt_match comment_match = {
        .name           = "comment",
        .match          = match,
-       .checkentry     = checkentry,
+       .matchsize      = sizeof(struct xt_comment_info),
        .me             = THIS_MODULE
 };
 
 static struct xt_match comment6_match = {
        .name           = "comment",
        .match          = match,
-       .checkentry     = checkentry,
+       .matchsize      = sizeof(struct xt_comment_info),
        .me             = THIS_MODULE
 };
 
index 150d2a4..f34ecb9 100644 (file)
@@ -44,6 +44,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -122,15 +123,13 @@ match(const struct sk_buff *skb,
 
 static int check(const char *tablename,
                 const void *ip,
+                const struct xt_match *match,
                 void *matchinfo,
                 unsigned int matchsize,
                 unsigned int hook_mask)
 {
        const struct xt_connbytes_info *sinfo = matchinfo;
 
-       if (matchsize != XT_ALIGN(sizeof(struct xt_connbytes_info)))
-               return 0;
-
        if (sinfo->what != XT_CONNBYTES_PKTS &&
            sinfo->what != XT_CONNBYTES_BYTES &&
            sinfo->what != XT_CONNBYTES_AVGPKT)
@@ -146,14 +145,16 @@ static int check(const char *tablename,
 
 static struct xt_match connbytes_match = {
        .name           = "connbytes",
-       .match          = &match,
-       .checkentry     = &check,
+       .match          = match,
+       .checkentry     = check,
+       .matchsize      = sizeof(struct xt_connbytes_info),
        .me             = THIS_MODULE
 };
 static struct xt_match connbytes6_match = {
        .name           = "connbytes",
-       .match          = &match,
-       .checkentry     = &check,
+       .match          = match,
+       .checkentry     = check,
+       .matchsize      = sizeof(struct xt_connbytes_info),
        .me             = THIS_MODULE
 };
 
index d06e925..5182247 100644 (file)
@@ -35,6 +35,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -52,37 +53,36 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *ip,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
-       struct xt_connmark_info *cm = 
-                               (struct xt_connmark_info *)matchinfo;
-       if (matchsize != XT_ALIGN(sizeof(struct xt_connmark_info)))
-               return 0;
+       struct xt_connmark_info *cm = (struct xt_connmark_info *)matchinfo;
 
        if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
                printk(KERN_WARNING "connmark: only support 32bit mark\n");
                return 0;
        }
-
        return 1;
 }
 
 static struct xt_match connmark_match = {
-       .name = "connmark",
-       .match = &match,
-       .checkentry = &checkentry,
-       .me = THIS_MODULE
+       .name           = "connmark",
+       .match          = match,
+       .matchsize      = sizeof(struct xt_connmark_info),
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
 };
+
 static struct xt_match connmark6_match = {
-       .name = "connmark",
-       .match = &match,
-       .checkentry = &checkentry,
-       .me = THIS_MODULE
+       .name           = "connmark",
+       .match          = match,
+       .matchsize      = sizeof(struct xt_connmark_info),
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
 };
 
-
 static int __init init(void)
 {
        int ret;
index ffdebc9..39fc294 100644 (file)
@@ -32,6 +32,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -118,6 +119,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -201,22 +203,10 @@ match(const struct sk_buff *skb,
 
 #endif /* CONFIG_NF_IP_CONNTRACK */
 
-static int check(const char *tablename,
-                const void *ip,
-                void *matchinfo,
-                unsigned int matchsize,
-                unsigned int hook_mask)
-{
-       if (matchsize != XT_ALIGN(sizeof(struct xt_conntrack_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct xt_match conntrack_match = {
        .name           = "conntrack",
-       .match          = &match,
-       .checkentry     = &check,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_conntrack_info),
        .me             = THIS_MODULE,
 };
 
index 779f42f..db6b70c 100644 (file)
@@ -95,6 +95,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -129,56 +130,34 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *inf,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
-       const struct ipt_ip *ip = inf;
-       const struct xt_dccp_info *info;
+       const struct xt_dccp_info *info = matchinfo;
 
-       info = (const struct xt_dccp_info *)matchinfo;
-
-       return ip->proto == IPPROTO_DCCP
-               && !(ip->invflags & XT_INV_PROTO)
-               && matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
-               && !(info->flags & ~XT_DCCP_VALID_FLAGS)
-               && !(info->invflags & ~XT_DCCP_VALID_FLAGS)
-               && !(info->invflags & ~info->flags);
-}
-
-static int
-checkentry6(const char *tablename,
-          const void *inf,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-{
-       const struct ip6t_ip6 *ip = inf;
-       const struct xt_dccp_info *info;
-
-       info = (const struct xt_dccp_info *)matchinfo;
-
-       return ip->proto == IPPROTO_DCCP
-               && !(ip->invflags & XT_INV_PROTO)
-               && matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
-               && !(info->flags & ~XT_DCCP_VALID_FLAGS)
+       return !(info->flags & ~XT_DCCP_VALID_FLAGS)
                && !(info->invflags & ~XT_DCCP_VALID_FLAGS)
                && !(info->invflags & ~info->flags);
 }
 
-
 static struct xt_match dccp_match = 
 { 
        .name           = "dccp",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_dccp_info),
+       .proto          = IPPROTO_DCCP,
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 static struct xt_match dccp6_match = 
 { 
        .name           = "dccp",
-       .match          = &match,
-       .checkentry     = &checkentry6,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_dccp_info),
+       .proto          = IPPROTO_DCCP,
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 38b6715..ef8e54d 100644 (file)
@@ -42,6 +42,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -89,6 +90,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -96,6 +98,7 @@ match(const struct sk_buff *skb,
 {
        const struct xt_helper_info *info = matchinfo;
        struct nf_conn *ct;
+       struct nf_conn_help *master_help;
        enum ip_conntrack_info ctinfo;
        int ret = info->invert;
        
@@ -111,7 +114,8 @@ match(const struct sk_buff *skb,
        }
 
        read_lock_bh(&nf_conntrack_lock);
-       if (!ct->master->helper) {
+       master_help = nfct_help(ct->master);
+       if (!master_help || !master_help->helper) {
                DEBUGP("xt_helper: master ct %p has no helper\n", 
                        exp->expectant);
                goto out_unlock;
@@ -123,8 +127,8 @@ match(const struct sk_buff *skb,
        if (info->name[0] == '\0')
                ret ^= 1;
        else
-               ret ^= !strncmp(ct->master->helper->name, info->name, 
-                               strlen(ct->master->helper->name));
+               ret ^= !strncmp(master_help->helper->name, info->name,
+                               strlen(master_help->helper->name));
 out_unlock:
        read_unlock_bh(&nf_conntrack_lock);
        return ret;
@@ -133,6 +137,7 @@ out_unlock:
 
 static int check(const char *tablename,
                 const void *inf,
+                const struct xt_match *match,
                 void *matchinfo,
                 unsigned int matchsize,
                 unsigned int hook_mask)
@@ -140,24 +145,21 @@ static int check(const char *tablename,
        struct xt_helper_info *info = matchinfo;
 
        info->name[29] = '\0';
-
-       /* verify size */
-       if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info)))
-               return 0;
-
        return 1;
 }
 
 static struct xt_match helper_match = {
        .name           = "helper",
-       .match          = &match,
-       .checkentry     = &check,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_helper_info),
+       .checkentry     = check,
        .me             = THIS_MODULE,
 };
 static struct xt_match helper6_match = {
        .name           = "helper",
-       .match          = &match,
-       .checkentry     = &check,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_helper_info),
+       .checkentry     = check,
        .me             = THIS_MODULE,
 };
 
index 39c8fae..b9e60f0 100644 (file)
@@ -24,6 +24,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -39,6 +40,7 @@ static int
 match6(const struct sk_buff *skb,
        const struct net_device *in,
        const struct net_device *out,
+       const struct xt_match *match,
        const void *matchinfo,
        int offset,
        unsigned int protoff,
@@ -50,29 +52,17 @@ match6(const struct sk_buff *skb,
        return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
 }
 
-static int
-checkentry(const char *tablename,
-           const void *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       if (matchsize != XT_ALIGN(sizeof(struct xt_length_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct xt_match length_match = {
        .name           = "length",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_length_info),
        .me             = THIS_MODULE,
 };
+
 static struct xt_match length6_match = {
        .name           = "length",
-       .match          = &match6,
-       .checkentry     = &checkentry,
+       .match          = match6,
+       .matchsize      = sizeof(struct xt_length_info),
        .me             = THIS_MODULE,
 };
 
index 15e4050..3049e6f 100644 (file)
@@ -68,6 +68,7 @@ static int
 ipt_limit_match(const struct sk_buff *skb,
                const struct net_device *in,
                const struct net_device *out,
+               const struct xt_match *match,
                const void *matchinfo,
                int offset,
                unsigned int protoff,
@@ -107,15 +108,13 @@ user2credits(u_int32_t user)
 static int
 ipt_limit_checkentry(const char *tablename,
                     const void *inf,
+                    const struct xt_match *match,
                     void *matchinfo,
                     unsigned int matchsize,
                     unsigned int hook_mask)
 {
        struct xt_rateinfo *r = matchinfo;
 
-       if (matchsize != XT_ALIGN(sizeof(struct xt_rateinfo)))
-               return 0;
-
        /* Check for overflow. */
        if (r->burst == 0
            || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
@@ -140,12 +139,14 @@ ipt_limit_checkentry(const char *tablename,
 static struct xt_match ipt_limit_reg = {
        .name           = "limit",
        .match          = ipt_limit_match,
+       .matchsize      = sizeof(struct xt_rateinfo),
        .checkentry     = ipt_limit_checkentry,
        .me             = THIS_MODULE,
 };
 static struct xt_match limit6_reg = {
        .name           = "limit",
        .match          = ipt_limit_match,
+       .matchsize      = sizeof(struct xt_rateinfo),
        .checkentry     = ipt_limit_checkentry,
        .me             = THIS_MODULE,
 };
index 0461dcb..b4559a4 100644 (file)
@@ -27,6 +27,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -42,37 +43,20 @@ match(const struct sk_buff *skb,
                ^ info->invert));
 }
 
-static int
-ipt_mac_checkentry(const char *tablename,
-                  const void *inf,
-                  void *matchinfo,
-                  unsigned int matchsize,
-                  unsigned int hook_mask)
-{
-       /* FORWARD isn't always valid, but it's nice to be able to do --RR */
-       if (hook_mask
-           & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
-               | (1 << NF_IP_FORWARD))) {
-               printk("xt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
-               return 0;
-       }
-
-       if (matchsize != XT_ALIGN(sizeof(struct xt_mac_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct xt_match mac_match = {
        .name           = "mac",
-       .match          = &match,
-       .checkentry     = &ipt_mac_checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_mac_info),
+       .hooks          = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) |
+                         (1 << NF_IP_FORWARD),
        .me             = THIS_MODULE,
 };
 static struct xt_match mac6_match = {
        .name           = "mac",
-       .match          = &match,
-       .checkentry     = &ipt_mac_checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_mac_info),
+       .hooks          = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) |
+                         (1 << NF_IP_FORWARD),
        .me             = THIS_MODULE,
 };
 
index 2a0ac62..c1a8f0f 100644 (file)
@@ -23,6 +23,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -36,34 +37,33 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
            const void *entry,
+          const struct xt_match *match,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
 {
        struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo;
 
-       if (matchsize != XT_ALIGN(sizeof(struct xt_mark_info)))
-               return 0;
-
        if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
                printk(KERN_WARNING "mark: only supports 32bit mark\n");
                return 0;
        }
-
        return 1;
 }
 
 static struct xt_match mark_match = {
        .name           = "mark",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_mark_info),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
 static struct xt_match mark6_match = {
        .name           = "mark",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_mark_info),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index 19bb57c..f788e8e 100644 (file)
@@ -26,6 +26,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -102,14 +103,13 @@ match_outdev:
 static int
 checkentry(const char *tablename,
                       const void *ip,
+                      const struct xt_match *match,
                       void *matchinfo,
                       unsigned int matchsize,
                       unsigned int hook_mask)
 {
        const struct xt_physdev_info *info = matchinfo;
 
-       if (matchsize != XT_ALIGN(sizeof(struct xt_physdev_info)))
-               return 0;
        if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
            info->bitmask & ~XT_PHYSDEV_OP_MASK)
                return 0;
@@ -118,15 +118,17 @@ checkentry(const char *tablename,
 
 static struct xt_match physdev_match = {
        .name           = "physdev",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_physdev_info),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
 static struct xt_match physdev6_match = {
        .name           = "physdev",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_physdev_info),
+       .checkentry     = checkentry,
        .me             = THIS_MODULE,
 };
 
index ab1b263..f38638d 100644 (file)
@@ -22,6 +22,7 @@ MODULE_ALIAS("ip6t_pkttype");
 static int match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -32,32 +33,20 @@ static int match(const struct sk_buff *skb,
        return (skb->pkt_type == info->pkttype) ^ info->invert;
 }
 
-static int checkentry(const char *tablename,
-                  const void *ip,
-                  void *matchinfo,
-                  unsigned int matchsize,
-                  unsigned int hook_mask)
-{
-       if (matchsize != XT_ALIGN(sizeof(struct xt_pkttype_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct xt_match pkttype_match = {
        .name           = "pkttype",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_pkttype_info),
        .me             = THIS_MODULE,
 };
+
 static struct xt_match pkttype6_match = {
        .name           = "pkttype",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_pkttype_info),
        .me             = THIS_MODULE,
 };
 
-
 static int __init init(void)
 {
        int ret;
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c
new file mode 100644 (file)
index 0000000..1ec2208
--- /dev/null
@@ -0,0 +1,209 @@
+/* IP tables module for matching IPsec policy
+ *
+ * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <net/xfrm.h>
+
+#include <linux/netfilter/xt_policy.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("Xtables IPsec policy matching module");
+MODULE_LICENSE("GPL");
+
+static inline int
+xt_addr_cmp(const union xt_policy_addr *a1, const union xt_policy_addr *m,
+           const union xt_policy_addr *a2, unsigned short family)
+{
+       switch (family) {
+       case AF_INET:
+               return (a1->a4.s_addr ^ a2->a4.s_addr) & m->a4.s_addr;
+       case AF_INET6:
+               return ipv6_masked_addr_cmp(&a1->a6, &m->a6, &a2->a6);
+       }
+       return 0;
+}
+
+static inline int
+match_xfrm_state(struct xfrm_state *x, const struct xt_policy_elem *e,
+                unsigned short family)
+{
+#define MATCH_ADDR(x,y,z)      (!e->match.x ||                        \
+                                (xt_addr_cmp(&e->x, &e->y, z, family) \
+                                 ^ e->invert.x))
+#define MATCH(x,y)             (!e->match.x || ((e->x == (y)) ^ e->invert.x))
+
+       return MATCH_ADDR(saddr, smask, (union xt_policy_addr *)&x->props.saddr) &&
+              MATCH_ADDR(daddr, dmask, (union xt_policy_addr *)&x->id.daddr.a4) &&
+              MATCH(proto, x->id.proto) &&
+              MATCH(mode, x->props.mode) &&
+              MATCH(spi, x->id.spi) &&
+              MATCH(reqid, x->props.reqid);
+}
+
+static int
+match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
+               unsigned short family)
+{
+       const struct xt_policy_elem *e;
+       struct sec_path *sp = skb->sp;
+       int strict = info->flags & XT_POLICY_MATCH_STRICT;
+       int i, pos;
+
+       if (sp == NULL)
+               return -1;
+       if (strict && info->len != sp->len)
+               return 0;
+
+       for (i = sp->len - 1; i >= 0; i--) {
+               pos = strict ? i - sp->len + 1 : 0;
+               if (pos >= info->len)
+                       return 0;
+               e = &info->pol[pos];
+
+               if (match_xfrm_state(sp->x[i].xvec, e, family)) {
+                       if (!strict)
+                               return 1;
+               } else if (strict)
+                       return 0;
+       }
+
+       return strict ? 1 : 0;
+}
+
+static int
+match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info,
+                unsigned short family)
+{
+       const struct xt_policy_elem *e;
+       struct dst_entry *dst = skb->dst;
+       int strict = info->flags & XT_POLICY_MATCH_STRICT;
+       int i, pos;
+
+       if (dst->xfrm == NULL)
+               return -1;
+
+       for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
+               pos = strict ? i : 0;
+               if (pos >= info->len)
+                       return 0;
+               e = &info->pol[pos];
+
+               if (match_xfrm_state(dst->xfrm, e, family)) {
+                       if (!strict)
+                               return 1;
+               } else if (strict)
+                       return 0;
+       }
+
+       return strict ? i == info->len : 0;
+}
+
+static int match(const struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 const struct xt_match *match,
+                 const void *matchinfo,
+                 int offset,
+                 unsigned int protoff,
+                 int *hotdrop)
+{
+       const struct xt_policy_info *info = matchinfo;
+       int ret;
+
+       if (info->flags & XT_POLICY_MATCH_IN)
+               ret = match_policy_in(skb, info, match->family);
+       else
+               ret = match_policy_out(skb, info, match->family);
+
+       if (ret < 0)
+               ret = info->flags & XT_POLICY_MATCH_NONE ? 1 : 0;
+       else if (info->flags & XT_POLICY_MATCH_NONE)
+               ret = 0;
+
+       return ret;
+}
+
+static int checkentry(const char *tablename, const void *ip_void,
+                      const struct xt_match *match,
+                      void *matchinfo, unsigned int matchsize,
+                      unsigned int hook_mask)
+{
+       struct xt_policy_info *info = matchinfo;
+
+       if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) {
+               printk(KERN_ERR "xt_policy: neither incoming nor "
+                               "outgoing policy selected\n");
+               return 0;
+       }
+       /* hook values are equal for IPv4 and IPv6 */
+       if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
+           && info->flags & XT_POLICY_MATCH_OUT) {
+               printk(KERN_ERR "xt_policy: output policy not valid in "
+                               "PRE_ROUTING and INPUT\n");
+               return 0;
+       }
+       if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
+           && info->flags & XT_POLICY_MATCH_IN) {
+               printk(KERN_ERR "xt_policy: input policy not valid in "
+                               "POST_ROUTING and OUTPUT\n");
+               return 0;
+       }
+       if (info->len > XT_POLICY_MAX_ELEM) {
+               printk(KERN_ERR "xt_policy: too many policy elements\n");
+               return 0;
+       }
+       return 1;
+}
+
+static struct xt_match policy_match = {
+       .name           = "policy",
+       .family         = AF_INET,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_policy_info),
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static struct xt_match policy6_match = {
+       .name           = "policy",
+       .family         = AF_INET6,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_policy_info),
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       ret = xt_register_match(AF_INET, &policy_match);
+       if (ret)
+               return ret;
+       ret = xt_register_match(AF_INET6, &policy6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &policy_match);
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET6, &policy6_match);
+       xt_unregister_match(AF_INET, &policy_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_ALIAS("ipt_policy");
+MODULE_ALIAS("ip6t_policy");
index 2b7e178..57815a0 100644 (file)
@@ -27,6 +27,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -38,30 +39,12 @@ match(const struct sk_buff *skb,
        return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
 }
 
-static int check(const char *tablename,
-                 const void *ip,
-                 void *matchinfo,
-                 unsigned int matchsize,
-                 unsigned int hook_mask)
-{
-       if (hook_mask
-           & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
-               (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) {
-               printk("xt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
-                      "LOCAL_IN or FORWARD.\n");
-               return 0;
-       }
-       if (matchsize != XT_ALIGN(sizeof(struct xt_realm_info))) {
-               printk("xt_realm: invalid matchsize.\n");
-               return 0;
-       }
-       return 1;
-}
-
 static struct xt_match realm_match = {
        .name           = "realm",
-       .match          = match, 
-       .checkentry     = check,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_realm_info),
+       .hooks          = (1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
+                         (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN),
        .me             = THIS_MODULE
 };
 
index 10fbfc5..f5d698b 100644 (file)
@@ -123,6 +123,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -162,19 +163,14 @@ match(const struct sk_buff *skb,
 static int
 checkentry(const char *tablename,
           const void *inf,
+          const struct xt_match *match,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
-       const struct xt_sctp_info *info;
-       const struct ipt_ip *ip = inf;
-
-       info = (const struct xt_sctp_info *)matchinfo;
+       const struct xt_sctp_info *info = matchinfo;
 
-       return ip->proto == IPPROTO_SCTP
-               && !(ip->invflags & XT_INV_PROTO)
-               && matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
-               && !(info->flags & ~XT_SCTP_VALID_FLAGS)
+       return !(info->flags & ~XT_SCTP_VALID_FLAGS)
                && !(info->invflags & ~XT_SCTP_VALID_FLAGS)
                && !(info->invflags & ~info->flags)
                && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || 
@@ -184,47 +180,23 @@ checkentry(const char *tablename,
                                | SCTP_CHUNK_MATCH_ONLY)));
 }
 
-static int
-checkentry6(const char *tablename,
-          const void *inf,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-{
-       const struct xt_sctp_info *info;
-       const struct ip6t_ip6 *ip = inf;
-
-       info = (const struct xt_sctp_info *)matchinfo;
-
-       return ip->proto == IPPROTO_SCTP
-               && !(ip->invflags & XT_INV_PROTO)
-               && matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
-               && !(info->flags & ~XT_SCTP_VALID_FLAGS)
-               && !(info->invflags & ~XT_SCTP_VALID_FLAGS)
-               && !(info->invflags & ~info->flags)
-               && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || 
-                       (info->chunk_match_type &
-                               (SCTP_CHUNK_MATCH_ALL 
-                               | SCTP_CHUNK_MATCH_ANY
-                               | SCTP_CHUNK_MATCH_ONLY)));
-}
-
-
-static struct xt_match sctp_match = 
-{ 
-       .name = "sctp",
-       .match = &match,
-       .checkentry = &checkentry,
-       .me = THIS_MODULE
-};
-static struct xt_match sctp6_match = 
-{ 
-       .name = "sctp",
-       .match = &match,
-       .checkentry = &checkentry6,
-       .me = THIS_MODULE
+static struct xt_match sctp_match = {
+       .name           = "sctp",
+       .match          = match,
+       .matchsize      = sizeof(struct xt_sctp_info),
+       .proto          = IPPROTO_SCTP,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
 };
 
+static struct xt_match sctp6_match = {
+       .name           = "sctp",
+       .match          = match,
+       .matchsize      = sizeof(struct xt_sctp_info),
+       .proto          = IPPROTO_SCTP,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
+};
 
 static int __init init(void)
 {
index 39ce808..b8ec00c 100644 (file)
@@ -24,6 +24,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -43,29 +44,17 @@ match(const struct sk_buff *skb,
        return (sinfo->statemask & statebit);
 }
 
-static int check(const char *tablename,
-                const void *ip,
-                void *matchinfo,
-                unsigned int matchsize,
-                unsigned int hook_mask)
-{
-       if (matchsize != XT_ALIGN(sizeof(struct xt_state_info)))
-               return 0;
-
-       return 1;
-}
-
 static struct xt_match state_match = {
        .name           = "state",
-       .match          = &match,
-       .checkentry     = &check,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_state_info),
        .me             = THIS_MODULE,
 };
 
 static struct xt_match state6_match = {
        .name           = "state",
-       .match          = &match,
-       .checkentry     = &check,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_state_info),
        .me             = THIS_MODULE,
 };
 
index 7c7d5c8..fccbad6 100644 (file)
@@ -24,6 +24,7 @@ MODULE_ALIAS("ip6t_string");
 static int match(const struct sk_buff *skb,
                 const struct net_device *in,
                 const struct net_device *out,
+                const struct xt_match *match,
                 const void *matchinfo,
                 int offset,
                 unsigned int protoff,
@@ -43,6 +44,7 @@ static int match(const struct sk_buff *skb,
 
 static int checkentry(const char *tablename,
                      const void *ip,
+                     const struct xt_match *match,
                      void *matchinfo,
                      unsigned int matchsize,
                      unsigned int hook_mask)
@@ -50,9 +52,6 @@ static int checkentry(const char *tablename,
        struct xt_string_info *conf = matchinfo;
        struct ts_config *ts_conf;
 
-       if (matchsize != XT_ALIGN(sizeof(struct xt_string_info)))
-               return 0;
-
        /* Damn, can't handle this case properly with iptables... */
        if (conf->from_offset > conf->to_offset)
                return 0;
@@ -67,7 +66,8 @@ static int checkentry(const char *tablename,
        return 1;
 }
 
-static void destroy(void *matchinfo, unsigned int matchsize)
+static void destroy(const struct xt_match *match, void *matchinfo,
+                   unsigned int matchsize)
 {
        textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
 }
@@ -75,6 +75,7 @@ static void destroy(void *matchinfo, unsigned int matchsize)
 static struct xt_match string_match = {
        .name           = "string",
        .match          = match,
+       .matchsize      = sizeof(struct xt_string_info),
        .checkentry     = checkentry,
        .destroy        = destroy,
        .me             = THIS_MODULE
@@ -82,6 +83,7 @@ static struct xt_match string_match = {
 static struct xt_match string6_match = {
        .name           = "string",
        .match          = match,
+       .matchsize      = sizeof(struct xt_string_info),
        .checkentry     = checkentry,
        .destroy        = destroy,
        .me             = THIS_MODULE
index acf7f53..4925fc9 100644 (file)
@@ -81,6 +81,7 @@ static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
+      const struct xt_match *match,
       const void *matchinfo,
       int offset,
       unsigned int protoff,
@@ -92,58 +93,19 @@ match(const struct sk_buff *skb,
                               info->invert, hotdrop);
 }
 
-static int
-checkentry(const char *tablename,
-           const void *ipinfo,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       const struct ipt_ip *ip = ipinfo;
-       if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
-               return 0;
-
-       /* Must specify -p tcp */
-       if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
-               printk("tcpmss: Only works on TCP packets\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static int
-checkentry6(const char *tablename,
-          const void *ipinfo,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       const struct ip6t_ip6 *ip = ipinfo;
-
-       if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
-               return 0;
-
-       /* Must specify -p tcp */
-       if (ip->proto != IPPROTO_TCP || (ip->invflags & XT_INV_PROTO)) {
-               printk("tcpmss: Only works on TCP packets\n");
-               return 0;
-       }
-
-       return 1;
-}
-
 static struct xt_match tcpmss_match = {
        .name           = "tcpmss",
-       .match          = &match,
-       .checkentry     = &checkentry,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_tcpmss_match_info),
+       .proto          = IPPROTO_TCP,
        .me             = THIS_MODULE,
 };
 
 static struct xt_match tcpmss6_match = {
        .name           = "tcpmss",
-       .match          = &match,
-       .checkentry     = &checkentry6,
+       .match          = match,
+       .matchsize      = sizeof(struct xt_tcpmss_match_info),
+       .proto          = IPPROTO_TCP,
        .me             = THIS_MODULE,
 };
 
index 669c811..b5cd0dd 100644 (file)
@@ -74,6 +74,7 @@ static int
 tcp_match(const struct sk_buff *skb,
          const struct net_device *in,
          const struct net_device *out,
+         const struct xt_match *match,
          const void *matchinfo,
          int offset,
          unsigned int protoff,
@@ -138,43 +139,22 @@ tcp_match(const struct sk_buff *skb,
 static int
 tcp_checkentry(const char *tablename,
               const void *info,
+              const struct xt_match *match,
               void *matchinfo,
               unsigned int matchsize,
               unsigned int hook_mask)
 {
-       const struct ipt_ip *ip = info;
        const struct xt_tcp *tcpinfo = matchinfo;
 
-       /* Must specify proto == TCP, and no unknown invflags */
-       return ip->proto == IPPROTO_TCP
-               && !(ip->invflags & XT_INV_PROTO)
-               && matchsize == XT_ALIGN(sizeof(struct xt_tcp))
-               && !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
+       /* Must specify no unknown invflags */
+       return !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
 }
 
-/* Called when user tries to insert an entry of this type. */
-static int
-tcp6_checkentry(const char *tablename,
-              const void *entry,
-              void *matchinfo,
-              unsigned int matchsize,
-              unsigned int hook_mask)
-{
-       const struct ip6t_ip6 *ipv6 = entry;
-       const struct xt_tcp *tcpinfo = matchinfo;
-
-       /* Must specify proto == TCP, and no unknown invflags */
-       return ipv6->proto == IPPROTO_TCP
-               && !(ipv6->invflags & XT_INV_PROTO)
-               && matchsize == XT_ALIGN(sizeof(struct xt_tcp))
-               && !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
-}
-
-
 static int
 udp_match(const struct sk_buff *skb,
          const struct net_device *in,
          const struct net_device *out,
+         const struct xt_match *match,
          const void *matchinfo,
          int offset,
          unsigned int protoff,
@@ -208,87 +188,49 @@ udp_match(const struct sk_buff *skb,
 static int
 udp_checkentry(const char *tablename,
               const void *info,
+              const struct xt_match *match,
               void *matchinfo,
-              unsigned int matchinfosize,
-              unsigned int hook_mask)
-{
-       const struct ipt_ip *ip = info;
-       const struct xt_udp *udpinfo = matchinfo;
-
-       /* Must specify proto == UDP, and no unknown invflags */
-       if (ip->proto != IPPROTO_UDP || (ip->invflags & XT_INV_PROTO)) {
-               duprintf("ipt_udp: Protocol %u != %u\n", ip->proto,
-                        IPPROTO_UDP);
-               return 0;
-       }
-       if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
-               duprintf("ipt_udp: matchsize %u != %u\n",
-                        matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
-               return 0;
-       }
-       if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
-               duprintf("ipt_udp: unknown flags %X\n",
-                        udpinfo->invflags);
-               return 0;
-       }
-
-       return 1;
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-udp6_checkentry(const char *tablename,
-              const void *entry,
-              void *matchinfo,
-              unsigned int matchinfosize,
+              unsigned int matchsize,
               unsigned int hook_mask)
 {
-       const struct ip6t_ip6 *ipv6 = entry;
-       const struct xt_udp *udpinfo = matchinfo;
+       const struct xt_tcp *udpinfo = matchinfo;
 
-       /* Must specify proto == UDP, and no unknown invflags */
-       if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & XT_INV_PROTO)) {
-               duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
-                        IPPROTO_UDP);
-               return 0;
-       }
-       if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
-               duprintf("ip6t_udp: matchsize %u != %u\n",
-                        matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
-               return 0;
-       }
-       if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
-               duprintf("ip6t_udp: unknown flags %X\n",
-                        udpinfo->invflags);
-               return 0;
-       }
-
-       return 1;
+       /* Must specify no unknown invflags */
+       return !(udpinfo->invflags & ~XT_UDP_INV_MASK);
 }
 
 static struct xt_match tcp_matchstruct = {
        .name           = "tcp",
-       .match          = &tcp_match,
-       .checkentry     = &tcp_checkentry,
+       .match          = tcp_match,
+       .matchsize      = sizeof(struct xt_tcp),
+       .proto          = IPPROTO_TCP,
+       .checkentry     = tcp_checkentry,
        .me             = THIS_MODULE,
 };
+
 static struct xt_match tcp6_matchstruct = {
        .name           = "tcp",
-       .match          = &tcp_match,
-       .checkentry     = &tcp6_checkentry,
+       .match          = tcp_match,
+       .matchsize      = sizeof(struct xt_tcp),
+       .proto          = IPPROTO_TCP,
+       .checkentry     = tcp_checkentry,
        .me             = THIS_MODULE,
 };
 
 static struct xt_match udp_matchstruct = {
        .name           = "udp",
-       .match          = &udp_match,
-       .checkentry     = &udp_checkentry,
+       .match          = udp_match,
+       .matchsize      = sizeof(struct xt_udp),
+       .proto          = IPPROTO_UDP,
+       .checkentry     = udp_checkentry,
        .me             = THIS_MODULE,
 };
 static struct xt_match udp6_matchstruct = {
        .name           = "udp",
-       .match          = &udp_match,
-       .checkentry     = &udp6_checkentry,
+       .match          = udp_match,
+       .matchsize      = sizeof(struct xt_udp),
+       .proto          = IPPROTO_UDP,
+       .checkentry     = udp_checkentry,
        .me             = THIS_MODULE,
 };
 
index 59dc7d1..d00a903 100644 (file)
@@ -106,6 +106,7 @@ struct nl_pid_hash {
 struct netlink_table {
        struct nl_pid_hash hash;
        struct hlist_head mc_list;
+       unsigned long *listeners;
        unsigned int nl_nonroot;
        unsigned int groups;
        struct module *module;
@@ -296,6 +297,24 @@ static inline int nl_pid_hash_dilute(struct nl_pid_hash *hash, int len)
 
 static const struct proto_ops netlink_ops;
 
+static void
+netlink_update_listeners(struct sock *sk)
+{
+       struct netlink_table *tbl = &nl_table[sk->sk_protocol];
+       struct hlist_node *node;
+       unsigned long mask;
+       unsigned int i;
+
+       for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) {
+               mask = 0;
+               sk_for_each_bound(sk, node, &tbl->mc_list)
+                       mask |= nlk_sk(sk)->groups[i];
+               tbl->listeners[i] = mask;
+       }
+       /* this function is only called with the netlink table "grabbed", which
+        * makes sure updates are visible before bind or setsockopt return. */
+}
+
 static int netlink_insert(struct sock *sk, u32 pid)
 {
        struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash;
@@ -456,12 +475,14 @@ static int netlink_release(struct socket *sock)
        if (nlk->module)
                module_put(nlk->module);
 
+       netlink_table_grab();
        if (nlk->flags & NETLINK_KERNEL_SOCKET) {
-               netlink_table_grab();
+               kfree(nl_table[sk->sk_protocol].listeners);
                nl_table[sk->sk_protocol].module = NULL;
                nl_table[sk->sk_protocol].registered = 0;
-               netlink_table_ungrab();
-       }
+       } else if (nlk->subscriptions)
+               netlink_update_listeners(sk);
+       netlink_table_ungrab();
 
        kfree(nlk->groups);
        nlk->groups = NULL;
@@ -589,6 +610,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
                                         hweight32(nladdr->nl_groups) -
                                         hweight32(nlk->groups[0]));
        nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; 
+       netlink_update_listeners(sk);
        netlink_table_ungrab();
 
        return 0;
@@ -807,6 +829,17 @@ retry:
        return netlink_sendskb(sk, skb, ssk->sk_protocol);
 }
 
+int netlink_has_listeners(struct sock *sk, unsigned int group)
+{
+       int res = 0;
+
+       BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET));
+       if (group - 1 < nl_table[sk->sk_protocol].groups)
+               res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners);
+       return res;
+}
+EXPORT_SYMBOL_GPL(netlink_has_listeners);
+
 static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
@@ -1011,6 +1044,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                else
                        __clear_bit(val - 1, nlk->groups);
                netlink_update_subscriptions(sk, subscriptions);
+               netlink_update_listeners(sk);
                netlink_table_ungrab();
                err = 0;
                break;
@@ -1237,6 +1271,7 @@ netlink_kernel_create(int unit, unsigned int groups,
        struct socket *sock;
        struct sock *sk;
        struct netlink_sock *nlk;
+       unsigned long *listeners = NULL;
 
        if (!nl_table)
                return NULL;
@@ -1250,6 +1285,13 @@ netlink_kernel_create(int unit, unsigned int groups,
        if (__netlink_create(sock, unit) < 0)
                goto out_sock_release;
 
+       if (groups < 32)
+               groups = 32;
+
+       listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
+       if (!listeners)
+               goto out_sock_release;
+
        sk = sock->sk;
        sk->sk_data_ready = netlink_data_ready;
        if (input)
@@ -1262,7 +1304,8 @@ netlink_kernel_create(int unit, unsigned int groups,
        nlk->flags |= NETLINK_KERNEL_SOCKET;
 
        netlink_table_grab();
-       nl_table[unit].groups = groups < 32 ? 32 : groups;
+       nl_table[unit].groups = groups;
+       nl_table[unit].listeners = listeners;
        nl_table[unit].module = module;
        nl_table[unit].registered = 1;
        netlink_table_ungrab();
@@ -1270,6 +1313,7 @@ netlink_kernel_create(int unit, unsigned int groups,
        return sk;
 
 out_sock_release:
+       kfree(listeners);
        sock_release(sock);
        return NULL;
 }
index 778b1e5..13eeee5 100644 (file)
@@ -434,7 +434,6 @@ config NET_EMATCH_TEXT
 
 config NET_CLS_ACT
        bool "Actions"
-       depends on EXPERIMENTAL
        select NET_ESTIMATOR
        ---help---
          Say Y here if you want to use traffic control actions. Actions
index 39a22a3..6056d20 100644 (file)
@@ -70,7 +70,8 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
        t->u.kernel.target = target;
 
        if (t->u.kernel.target->checkentry
-           && !t->u.kernel.target->checkentry(table, NULL, t->data,
+           && !t->u.kernel.target->checkentry(table, NULL,
+                                              t->u.kernel.target, t->data,
                                               t->u.target_size - sizeof(*t),
                                               hook)) {
                DPRINTK("ipt_init_target: check failed for `%s'.\n",
@@ -86,7 +87,7 @@ static void
 ipt_destroy_target(struct ipt_entry_target *t)
 {
        if (t->u.kernel.target->destroy)
-               t->u.kernel.target->destroy(t->data,
+               t->u.kernel.target->destroy(t->u.kernel.target, t->data,
                                            t->u.target_size - sizeof(*t));
         module_put(t->u.kernel.target->me);
 }
@@ -224,8 +225,9 @@ tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
        /* iptables targets take a double skb pointer in case the skb
         * needs to be replaced. We don't own the skb, so this must not
         * happen. The pskb_expand_head above should make sure of this */
-       ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL,
-                                           p->hook, p->t->data, NULL);
+       ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, p->hook,
+                                           p->t->u.kernel.target, p->t->data,
+                                           NULL);
        switch (ret) {
        case NF_ACCEPT:
                result = TC_ACT_OK;
index 93ebce4..ac7cb60 100644 (file)
@@ -638,6 +638,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
            sch,p,flow,skb,tcm);
        if (!find_flow(p,flow)) return -EINVAL;
        tcm->tcm_handle = flow->classid;
+       tcm->tcm_info = flow->q->handle;
        rta = (struct rtattr *) b;
        RTA_PUT(skb,TCA_OPTIONS,0,NULL);
        RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr);
index 13e0e7b..f6320ca 100644 (file)
@@ -438,6 +438,7 @@ static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
                return -EINVAL;
 
        tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl-1);
+       tcm->tcm_info = p->q->handle;
 
        opts = RTA_NEST(skb, TCA_OPTIONS);
        RTA_PUT_U8(skb,TCA_DSMARK_MASK, p->mask[cl-1]);
index 99ceb91..31eb837 100644 (file)
@@ -234,7 +234,7 @@ static void dev_watchdog_down(struct net_device *dev)
 {
        spin_lock_bh(&dev->xmit_lock);
        if (del_timer(&dev->watchdog_timer))
-               __dev_put(dev);
+               dev_put(dev);
        spin_unlock_bh(&dev->xmit_lock);
 }
 
index ba52832..7228d30 100644 (file)
@@ -252,9 +252,9 @@ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
 static unsigned int netem_drop(struct Qdisc* sch)
 {
        struct netem_sched_data *q = qdisc_priv(sch);
-       unsigned int len;
+       unsigned int len = 0;
 
-       if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
+       if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
                sch->q.qlen--;
                sch->qstats.drops++;
        }
index 1641db3..3395ca7 100644 (file)
@@ -165,7 +165,7 @@ static unsigned int prio_drop(struct Qdisc* sch)
 
        for (prio = q->bands-1; prio >= 0; prio--) {
                qdisc = q->queues[prio];
-               if ((len = qdisc->ops->drop(qdisc)) != 0) {
+               if (qdisc->ops->drop && (len = qdisc->ops->drop(qdisc)) != 0) {
                        sch->q.qlen--;
                        return len;
                }
index dccfa44..2be563c 100644 (file)
@@ -44,6 +44,7 @@ struct red_sched_data
        unsigned char           flags;
        struct red_parms        parms;
        struct red_stats        stats;
+       struct Qdisc            *qdisc;
 };
 
 static inline int red_use_ecn(struct red_sched_data *q)
@@ -59,8 +60,10 @@ static inline int red_use_harddrop(struct red_sched_data *q)
 static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
        struct red_sched_data *q = qdisc_priv(sch);
+       struct Qdisc *child = q->qdisc;
+       int ret;
 
-       q->parms.qavg = red_calc_qavg(&q->parms, sch->qstats.backlog);
+       q->parms.qavg = red_calc_qavg(&q->parms, child->qstats.backlog);
 
        if (red_is_idling(&q->parms))
                red_end_of_idle_period(&q->parms);
@@ -91,11 +94,16 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
                        break;
        }
 
-       if (sch->qstats.backlog + skb->len <= q->limit)
-               return qdisc_enqueue_tail(skb, sch);
-
-       q->stats.pdrop++;
-       return qdisc_drop(skb, sch);
+       ret = child->enqueue(skb, child);
+       if (likely(ret == NET_XMIT_SUCCESS)) {
+               sch->bstats.bytes += skb->len;
+               sch->bstats.packets++;
+               sch->q.qlen++;
+       } else {
+               q->stats.pdrop++;
+               sch->qstats.drops++;
+       }
+       return ret;
 
 congestion_drop:
        qdisc_drop(skb, sch);
@@ -105,21 +113,30 @@ congestion_drop:
 static int red_requeue(struct sk_buff *skb, struct Qdisc* sch)
 {
        struct red_sched_data *q = qdisc_priv(sch);
+       struct Qdisc *child = q->qdisc;
+       int ret;
 
        if (red_is_idling(&q->parms))
                red_end_of_idle_period(&q->parms);
 
-       return qdisc_requeue(skb, sch);
+       ret = child->ops->requeue(skb, child);
+       if (likely(ret == NET_XMIT_SUCCESS)) {
+               sch->qstats.requeues++;
+               sch->q.qlen++;
+       }
+       return ret;
 }
 
 static struct sk_buff * red_dequeue(struct Qdisc* sch)
 {
        struct sk_buff *skb;
        struct red_sched_data *q = qdisc_priv(sch);
+       struct Qdisc *child = q->qdisc;
 
-       skb = qdisc_dequeue_head(sch);
-
-       if (skb == NULL && !red_is_idling(&q->parms))
+       skb = child->dequeue(child);
+       if (skb)
+               sch->q.qlen--;
+       else if (!red_is_idling(&q->parms))
                red_start_of_idle_period(&q->parms);
 
        return skb;
@@ -127,14 +144,14 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
 
 static unsigned int red_drop(struct Qdisc* sch)
 {
-       struct sk_buff *skb;
        struct red_sched_data *q = qdisc_priv(sch);
+       struct Qdisc *child = q->qdisc;
+       unsigned int len;
 
-       skb = qdisc_dequeue_tail(sch);
-       if (skb) {
-               unsigned int len = skb->len;
+       if (child->ops->drop && (len = child->ops->drop(child)) > 0) {
                q->stats.other++;
-               qdisc_drop(skb, sch);
+               sch->qstats.drops++;
+               sch->q.qlen--;
                return len;
        }
 
@@ -148,15 +165,48 @@ static void red_reset(struct Qdisc* sch)
 {
        struct red_sched_data *q = qdisc_priv(sch);
 
-       qdisc_reset_queue(sch);
+       qdisc_reset(q->qdisc);
+       sch->q.qlen = 0;
        red_restart(&q->parms);
 }
 
+static void red_destroy(struct Qdisc *sch)
+{
+       struct red_sched_data *q = qdisc_priv(sch);
+       qdisc_destroy(q->qdisc);
+}
+
+static struct Qdisc *red_create_dflt(struct net_device *dev, u32 limit)
+{
+       struct Qdisc *q = qdisc_create_dflt(dev, &bfifo_qdisc_ops);
+       struct rtattr *rta;
+       int ret;
+
+       if (q) {
+               rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)),
+                             GFP_KERNEL);
+               if (rta) {
+                       rta->rta_type = RTM_NEWQDISC;
+                       rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
+                       ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
+
+                       ret = q->ops->change(q, rta);
+                       kfree(rta);
+
+                       if (ret == 0)
+                               return q;
+               }
+               qdisc_destroy(q);
+       }
+       return NULL;
+}
+
 static int red_change(struct Qdisc *sch, struct rtattr *opt)
 {
        struct red_sched_data *q = qdisc_priv(sch);
        struct rtattr *tb[TCA_RED_MAX];
        struct tc_red_qopt *ctl;
+       struct Qdisc *child = NULL;
 
        if (opt == NULL || rtattr_parse_nested(tb, TCA_RED_MAX, opt))
                return -EINVAL;
@@ -169,9 +219,17 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
 
        ctl = RTA_DATA(tb[TCA_RED_PARMS-1]);
 
+       if (ctl->limit > 0) {
+               child = red_create_dflt(sch->dev, ctl->limit);
+               if (child == NULL)
+                       return -ENOMEM;
+       }
+
        sch_tree_lock(sch);
        q->flags = ctl->flags;
        q->limit = ctl->limit;
+       if (child)
+               qdisc_destroy(xchg(&q->qdisc, child));
 
        red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
                                 ctl->Plog, ctl->Scell_log,
@@ -186,6 +244,9 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
 
 static int red_init(struct Qdisc* sch, struct rtattr *opt)
 {
+       struct red_sched_data *q = qdisc_priv(sch);
+
+       q->qdisc = &noop_qdisc;
        return red_change(sch, opt);
 }
 
@@ -224,15 +285,101 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
        return gnet_stats_copy_app(d, &st, sizeof(st));
 }
 
+static int red_dump_class(struct Qdisc *sch, unsigned long cl,
+                         struct sk_buff *skb, struct tcmsg *tcm)
+{
+       struct red_sched_data *q = qdisc_priv(sch);
+
+       if (cl != 1)
+               return -ENOENT;
+       tcm->tcm_handle |= TC_H_MIN(1);
+       tcm->tcm_info = q->qdisc->handle;
+       return 0;
+}
+
+static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
+                    struct Qdisc **old)
+{
+       struct red_sched_data *q = qdisc_priv(sch);
+
+       if (new == NULL)
+               new = &noop_qdisc;
+
+       sch_tree_lock(sch);
+       *old = xchg(&q->qdisc, new);
+       qdisc_reset(*old);
+       sch->q.qlen = 0;
+       sch_tree_unlock(sch);
+       return 0;
+}
+
+static struct Qdisc *red_leaf(struct Qdisc *sch, unsigned long arg)
+{
+       struct red_sched_data *q = qdisc_priv(sch);
+       return q->qdisc;
+}
+
+static unsigned long red_get(struct Qdisc *sch, u32 classid)
+{
+       return 1;
+}
+
+static void red_put(struct Qdisc *sch, unsigned long arg)
+{
+       return;
+}
+
+static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+                           struct rtattr **tca, unsigned long *arg)
+{
+       return -ENOSYS;
+}
+
+static int red_delete(struct Qdisc *sch, unsigned long cl)
+{
+       return -ENOSYS;
+}
+
+static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker)
+{
+       if (!walker->stop) {
+               if (walker->count >= walker->skip)
+                       if (walker->fn(sch, 1, walker) < 0) {
+                               walker->stop = 1;
+                               return;
+                       }
+               walker->count++;
+       }
+}
+
+static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl)
+{
+       return NULL;
+}
+
+static struct Qdisc_class_ops red_class_ops = {
+       .graft          =       red_graft,
+       .leaf           =       red_leaf,
+       .get            =       red_get,
+       .put            =       red_put,
+       .change         =       red_change_class,
+       .delete         =       red_delete,
+       .walk           =       red_walk,
+       .tcf_chain      =       red_find_tcf,
+       .dump           =       red_dump_class,
+};
+
 static struct Qdisc_ops red_qdisc_ops = {
        .id             =       "red",
        .priv_size      =       sizeof(struct red_sched_data),
+       .cl_ops         =       &red_class_ops,
        .enqueue        =       red_enqueue,
        .dequeue        =       red_dequeue,
        .requeue        =       red_requeue,
        .drop           =       red_drop,
        .init           =       red_init,
        .reset          =       red_reset,
+       .destroy        =       red_destroy,
        .change         =       red_change,
        .dump           =       red_dump,
        .dump_stats     =       red_dump_stats,
index 86d8da0..e057768 100644 (file)
@@ -232,6 +232,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
                sfq_dec(q, x);
                sch->q.qlen--;
                sch->qstats.drops++;
+               sch->qstats.backlog -= len;
                return len;
        }
 
@@ -248,6 +249,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
                sch->q.qlen--;
                q->ht[q->hash[d]] = SFQ_DEPTH;
                sch->qstats.drops++;
+               sch->qstats.backlog -= len;
                return len;
        }
 
@@ -266,6 +268,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
                q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
                q->hash[x] = hash;
        }
+       sch->qstats.backlog += skb->len;
        __skb_queue_tail(&q->qs[x], skb);
        sfq_inc(q, x);
        if (q->qs[x].qlen == 1) {               /* The flow is new */
@@ -301,6 +304,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
                q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
                q->hash[x] = hash;
        }
+       sch->qstats.backlog += skb->len;
        __skb_queue_head(&q->qs[x], skb);
        sfq_inc(q, x);
        if (q->qs[x].qlen == 1) {               /* The flow is new */
@@ -344,6 +348,7 @@ sfq_dequeue(struct Qdisc* sch)
        skb = __skb_dequeue(&q->qs[a]);
        sfq_dec(q, a);
        sch->q.qlen--;
+       sch->qstats.backlog -= skb->len;
 
        /* Is the slot empty? */
        if (q->qs[a].qlen == 0) {
index cb9711e..d8e03c7 100644 (file)
@@ -177,9 +177,9 @@ static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch)
 static unsigned int tbf_drop(struct Qdisc* sch)
 {
        struct tbf_sched_data *q = qdisc_priv(sch);
-       unsigned int len;
+       unsigned int len = 0;
 
-       if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
+       if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
                sch->q.qlen--;
                sch->qstats.drops++;
        }
@@ -341,13 +341,14 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
        if (max_size < 0)
                goto done;
 
-       if (q->qdisc == &noop_qdisc) {
+       if (qopt->limit > 0) {
                if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL)
                        goto done;
        }
 
        sch_tree_lock(sch);
-       if (child) q->qdisc = child;
+       if (child)
+               qdisc_destroy(xchg(&q->qdisc, child));
        q->limit = qopt->limit;
        q->mtu = qopt->mtu;
        q->max_size = max_size;
index 2e26612..c20d282 100644 (file)
@@ -861,23 +861,27 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
 }
 
 static const struct proto_ops inet6_seqpacket_ops = {
-       .family     = PF_INET6,
-       .owner      = THIS_MODULE,
-       .release    = inet6_release,
-       .bind       = inet6_bind,
-       .connect    = inet_dgram_connect,
-       .socketpair = sock_no_socketpair,
-       .accept     = inet_accept,
-       .getname    = inet6_getname,
-       .poll       = sctp_poll,
-       .ioctl      = inet6_ioctl,
-       .listen     = sctp_inet_listen,
-       .shutdown   = inet_shutdown,
-       .setsockopt = sock_common_setsockopt,
-       .getsockopt = sock_common_getsockopt,
-       .sendmsg    = inet_sendmsg,
-       .recvmsg    = sock_common_recvmsg,
-       .mmap       = sock_no_mmap,
+       .family            = PF_INET6,
+       .owner             = THIS_MODULE,
+       .release           = inet6_release,
+       .bind              = inet6_bind,
+       .connect           = inet_dgram_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = inet_accept,
+       .getname           = inet6_getname,
+       .poll              = sctp_poll,
+       .ioctl             = inet6_ioctl,
+       .listen            = sctp_inet_listen,
+       .shutdown          = inet_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 static struct inet_protosw sctpv6_seqpacket_protosw = {
@@ -911,31 +915,35 @@ static struct inet6_protocol sctpv6_protocol = {
 };
 
 static struct sctp_af sctp_ipv6_specific = {
-       .sctp_xmit       = sctp_v6_xmit,
-       .setsockopt      = ipv6_setsockopt,
-       .getsockopt      = ipv6_getsockopt,
-       .get_dst         = sctp_v6_get_dst,
-       .get_saddr       = sctp_v6_get_saddr,
-       .copy_addrlist   = sctp_v6_copy_addrlist,
-       .from_skb        = sctp_v6_from_skb,
-       .from_sk         = sctp_v6_from_sk,
-       .to_sk_saddr     = sctp_v6_to_sk_saddr,
-       .to_sk_daddr     = sctp_v6_to_sk_daddr,
-       .from_addr_param = sctp_v6_from_addr_param,
-       .to_addr_param   = sctp_v6_to_addr_param,
-       .dst_saddr       = sctp_v6_dst_saddr,
-       .cmp_addr        = sctp_v6_cmp_addr,
-       .scope           = sctp_v6_scope,
-       .addr_valid      = sctp_v6_addr_valid,
-       .inaddr_any      = sctp_v6_inaddr_any,
-       .is_any          = sctp_v6_is_any,
-       .available       = sctp_v6_available,
-       .skb_iif         = sctp_v6_skb_iif,
-       .is_ce           = sctp_v6_is_ce,
-       .seq_dump_addr   = sctp_v6_seq_dump_addr,
-       .net_header_len  = sizeof(struct ipv6hdr),
-       .sockaddr_len    = sizeof(struct sockaddr_in6),
-       .sa_family       = AF_INET6,
+       .sa_family         = AF_INET6,
+       .sctp_xmit         = sctp_v6_xmit,
+       .setsockopt        = ipv6_setsockopt,
+       .getsockopt        = ipv6_getsockopt,
+       .get_dst           = sctp_v6_get_dst,
+       .get_saddr         = sctp_v6_get_saddr,
+       .copy_addrlist     = sctp_v6_copy_addrlist,
+       .from_skb          = sctp_v6_from_skb,
+       .from_sk           = sctp_v6_from_sk,
+       .to_sk_saddr       = sctp_v6_to_sk_saddr,
+       .to_sk_daddr       = sctp_v6_to_sk_daddr,
+       .from_addr_param   = sctp_v6_from_addr_param,
+       .to_addr_param     = sctp_v6_to_addr_param,
+       .dst_saddr         = sctp_v6_dst_saddr,
+       .cmp_addr          = sctp_v6_cmp_addr,
+       .scope             = sctp_v6_scope,
+       .addr_valid        = sctp_v6_addr_valid,
+       .inaddr_any        = sctp_v6_inaddr_any,
+       .is_any            = sctp_v6_is_any,
+       .available         = sctp_v6_available,
+       .skb_iif           = sctp_v6_skb_iif,
+       .is_ce             = sctp_v6_is_ce,
+       .seq_dump_addr     = sctp_v6_seq_dump_addr,
+       .net_header_len    = sizeof(struct ipv6hdr),
+       .sockaddr_len      = sizeof(struct sockaddr_in6),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ipv6_setsockopt,
+       .compat_getsockopt = compat_ipv6_getsockopt,
+#endif
 };
 
 static struct sctp_pf sctp_pf_inet6_specific = {
index de693b4..2088aa9 100644 (file)
@@ -831,24 +831,28 @@ static struct notifier_block sctp_inetaddr_notifier = {
 
 /* Socket operations.  */
 static const struct proto_ops inet_seqpacket_ops = {
-       .family      = PF_INET,
-       .owner       = THIS_MODULE,
-       .release     = inet_release,       /* Needs to be wrapped... */
-       .bind        = inet_bind,
-       .connect     = inet_dgram_connect,
-       .socketpair  = sock_no_socketpair,
-       .accept      = inet_accept,
-       .getname     = inet_getname,      /* Semantics are different.  */
-       .poll        = sctp_poll,
-       .ioctl       = inet_ioctl,
-       .listen      = sctp_inet_listen,
-       .shutdown    = inet_shutdown,     /* Looks harmless.  */
-       .setsockopt  = sock_common_setsockopt,   /* IP_SOL IP_OPTION is a problem. */
-       .getsockopt  = sock_common_getsockopt,
-       .sendmsg     = inet_sendmsg,
-       .recvmsg     = sock_common_recvmsg,
-       .mmap        = sock_no_mmap,
-       .sendpage    = sock_no_sendpage,
+       .family            = PF_INET,
+       .owner             = THIS_MODULE,
+       .release           = inet_release,      /* Needs to be wrapped... */
+       .bind              = inet_bind,
+       .connect           = inet_dgram_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = inet_accept,
+       .getname           = inet_getname,      /* Semantics are different.  */
+       .poll              = sctp_poll,
+       .ioctl             = inet_ioctl,
+       .listen            = sctp_inet_listen,
+       .shutdown          = inet_shutdown,     /* Looks harmless.  */
+       .setsockopt        = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem */
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 /* Registration with AF_INET family.  */
@@ -880,31 +884,35 @@ static struct net_protocol sctp_protocol = {
 
 /* IPv4 address related functions.  */
 static struct sctp_af sctp_ipv4_specific = {
-       .sctp_xmit      = sctp_v4_xmit,
-       .setsockopt     = ip_setsockopt,
-       .getsockopt     = ip_getsockopt,
-       .get_dst        = sctp_v4_get_dst,
-       .get_saddr      = sctp_v4_get_saddr,
-       .copy_addrlist  = sctp_v4_copy_addrlist,
-       .from_skb       = sctp_v4_from_skb,
-       .from_sk        = sctp_v4_from_sk,
-       .to_sk_saddr    = sctp_v4_to_sk_saddr,
-       .to_sk_daddr    = sctp_v4_to_sk_daddr,
-       .from_addr_param= sctp_v4_from_addr_param,
-       .to_addr_param  = sctp_v4_to_addr_param,        
-       .dst_saddr      = sctp_v4_dst_saddr,
-       .cmp_addr       = sctp_v4_cmp_addr,
-       .addr_valid     = sctp_v4_addr_valid,
-       .inaddr_any     = sctp_v4_inaddr_any,
-       .is_any         = sctp_v4_is_any,
-       .available      = sctp_v4_available,
-       .scope          = sctp_v4_scope,
-       .skb_iif        = sctp_v4_skb_iif,
-       .is_ce          = sctp_v4_is_ce,
-       .seq_dump_addr  = sctp_v4_seq_dump_addr,
-       .net_header_len = sizeof(struct iphdr),
-       .sockaddr_len   = sizeof(struct sockaddr_in),
-       .sa_family      = AF_INET,
+       .sa_family         = AF_INET,
+       .sctp_xmit         = sctp_v4_xmit,
+       .setsockopt        = ip_setsockopt,
+       .getsockopt        = ip_getsockopt,
+       .get_dst           = sctp_v4_get_dst,
+       .get_saddr         = sctp_v4_get_saddr,
+       .copy_addrlist     = sctp_v4_copy_addrlist,
+       .from_skb          = sctp_v4_from_skb,
+       .from_sk           = sctp_v4_from_sk,
+       .to_sk_saddr       = sctp_v4_to_sk_saddr,
+       .to_sk_daddr       = sctp_v4_to_sk_daddr,
+       .from_addr_param   = sctp_v4_from_addr_param,
+       .to_addr_param     = sctp_v4_to_addr_param,
+       .dst_saddr         = sctp_v4_dst_saddr,
+       .cmp_addr          = sctp_v4_cmp_addr,
+       .addr_valid        = sctp_v4_addr_valid,
+       .inaddr_any        = sctp_v4_inaddr_any,
+       .is_any            = sctp_v4_is_any,
+       .available         = sctp_v4_available,
+       .scope             = sctp_v4_scope,
+       .skb_iif           = sctp_v4_skb_iif,
+       .is_ce             = sctp_v4_is_ce,
+       .seq_dump_addr     = sctp_v4_seq_dump_addr,
+       .net_header_len    = sizeof(struct iphdr),
+       .sockaddr_len      = sizeof(struct sockaddr_in),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ip_setsockopt,
+       .compat_getsockopt = compat_ip_getsockopt,
+#endif
 };
 
 struct sctp_pf *sctp_get_pf_specific(sa_family_t family) {
index 7e1bdef..e3c21d5 100644 (file)
@@ -68,6 +68,7 @@
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 #include <linux/wanrouter.h>
 #include <linux/if_bridge.h>
 #include <linux/if_frad.h>
@@ -348,8 +349,8 @@ static struct dentry_operations sockfs_dentry_operations = {
 /*
  *     Obtains the first available file descriptor and sets it up for use.
  *
- *     This function creates file structure and maps it to fd space
- *     of current process. On success it returns file descriptor
+ *     These functions create file structures and maps them to fd space
+ *     of the current process. On success it returns file descriptor
  *     and file struct implicitly stored in sock->file.
  *     Note that another thread may close file descriptor before we return
  *     from this function. We use the fact that now we do not refer
@@ -362,53 +363,90 @@ static struct dentry_operations sockfs_dentry_operations = {
  *     but we take care of internal coherence yet.
  */
 
-int sock_map_fd(struct socket *sock)
+static int sock_alloc_fd(struct file **filep)
 {
        int fd;
-       struct qstr this;
-       char name[32];
-
-       /*
-        *      Find a file descriptor suitable for return to the user. 
-        */
 
        fd = get_unused_fd();
-       if (fd >= 0) {
+       if (likely(fd >= 0)) {
                struct file *file = get_empty_filp();
 
-               if (!file) {
+               *filep = file;
+               if (unlikely(!file)) {
                        put_unused_fd(fd);
-                       fd = -ENFILE;
-                       goto out;
+                       return -ENFILE;
                }
+       } else
+               *filep = NULL;
+       return fd;
+}
+
+static int sock_attach_fd(struct socket *sock, struct file *file)
+{
+       struct qstr this;
+       char name[32];
+
+       this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
+       this.name = name;
+       this.hash = SOCK_INODE(sock)->i_ino;
 
-               this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
-               this.name = name;
-               this.hash = SOCK_INODE(sock)->i_ino;
+       file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
+       if (unlikely(!file->f_dentry))
+               return -ENOMEM;
+
+       file->f_dentry->d_op = &sockfs_dentry_operations;
+       d_add(file->f_dentry, SOCK_INODE(sock));
+       file->f_vfsmnt = mntget(sock_mnt);
+       file->f_mapping = file->f_dentry->d_inode->i_mapping;
+
+       sock->file = file;
+       file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
+       file->f_mode = FMODE_READ | FMODE_WRITE;
+       file->f_flags = O_RDWR;
+       file->f_pos = 0;
+       file->private_data = sock;
+
+       return 0;
+}
 
-               file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
-               if (!file->f_dentry) {
-                       put_filp(file);
+int sock_map_fd(struct socket *sock)
+{
+       struct file *newfile;
+       int fd = sock_alloc_fd(&newfile);
+
+       if (likely(fd >= 0)) {
+               int err = sock_attach_fd(sock, newfile);
+
+               if (unlikely(err < 0)) {
+                       put_filp(newfile);
                        put_unused_fd(fd);
-                       fd = -ENOMEM;
-                       goto out;
+                       return err;
                }
-               file->f_dentry->d_op = &sockfs_dentry_operations;
-               d_add(file->f_dentry, SOCK_INODE(sock));
-               file->f_vfsmnt = mntget(sock_mnt);
-               file->f_mapping = file->f_dentry->d_inode->i_mapping;
+               fd_install(fd, newfile);
+       }
+       return fd;
+}
 
-               sock->file = file;
-               file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
-               file->f_mode = FMODE_READ | FMODE_WRITE;
-               file->f_flags = O_RDWR;
-               file->f_pos = 0;
-               file->private_data = sock;
-               fd_install(fd, file);
+static struct socket *sock_from_file(struct file *file, int *err)
+{
+       struct inode *inode;
+       struct socket *sock;
+
+       if (file->f_op == &socket_file_ops)
+               return file->private_data;      /* set in sock_map_fd */
+
+       inode = file->f_dentry->d_inode;
+       if (!S_ISSOCK(inode->i_mode)) {
+               *err = -ENOTSOCK;
+               return NULL;
        }
 
-out:
-       return fd;
+       sock = SOCKET_I(inode);
+       if (sock->file != file) {
+               printk(KERN_ERR "socki_lookup: socket file changed!\n");
+               sock->file = file;
+       }
+       return sock;
 }
 
 /**
@@ -427,31 +465,31 @@ out:
 struct socket *sockfd_lookup(int fd, int *err)
 {
        struct file *file;
-       struct inode *inode;
        struct socket *sock;
 
-       if (!(file = fget(fd)))
-       {
+       if (!(file = fget(fd))) {
                *err = -EBADF;
                return NULL;
        }
-
-       if (file->f_op == &socket_file_ops)
-               return file->private_data;      /* set in sock_map_fd */
-
-       inode = file->f_dentry->d_inode;
-       if (!S_ISSOCK(inode->i_mode)) {
-               *err = -ENOTSOCK;
+       sock = sock_from_file(file, err);
+       if (!sock)
                fput(file);
-               return NULL;
-       }
+       return sock;
+}
 
-       sock = SOCKET_I(inode);
-       if (sock->file != file) {
-               printk(KERN_ERR "socki_lookup: socket file changed!\n");
-               sock->file = file;
+static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
+{
+       struct file *file;
+       struct socket *sock;
+
+       file = fget_light(fd, fput_needed);
+       if (file) {
+               sock = sock_from_file(file, err);
+               if (sock)
+                       return sock;
+               fput_light(file, *fput_needed);
        }
-       return sock;
+       return NULL;
 }
 
 /**
@@ -789,36 +827,36 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
  * with module unload.
  */
 
-static DECLARE_MUTEX(br_ioctl_mutex);
+static DEFINE_MUTEX(br_ioctl_mutex);
 static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL;
 
 void brioctl_set(int (*hook)(unsigned int, void __user *))
 {
-       down(&br_ioctl_mutex);
+       mutex_lock(&br_ioctl_mutex);
        br_ioctl_hook = hook;
-       up(&br_ioctl_mutex);
+       mutex_unlock(&br_ioctl_mutex);
 }
 EXPORT_SYMBOL(brioctl_set);
 
-static DECLARE_MUTEX(vlan_ioctl_mutex);
+static DEFINE_MUTEX(vlan_ioctl_mutex);
 static int (*vlan_ioctl_hook)(void __user *arg);
 
 void vlan_ioctl_set(int (*hook)(void __user *))
 {
-       down(&vlan_ioctl_mutex);
+       mutex_lock(&vlan_ioctl_mutex);
        vlan_ioctl_hook = hook;
-       up(&vlan_ioctl_mutex);
+       mutex_unlock(&vlan_ioctl_mutex);
 }
 EXPORT_SYMBOL(vlan_ioctl_set);
 
-static DECLARE_MUTEX(dlci_ioctl_mutex);
+static DEFINE_MUTEX(dlci_ioctl_mutex);
 static int (*dlci_ioctl_hook)(unsigned int, void __user *);
 
 void dlci_ioctl_set(int (*hook)(unsigned int, void __user *))
 {
-       down(&dlci_ioctl_mutex);
+       mutex_lock(&dlci_ioctl_mutex);
        dlci_ioctl_hook = hook;
-       up(&dlci_ioctl_mutex);
+       mutex_unlock(&dlci_ioctl_mutex);
 }
 EXPORT_SYMBOL(dlci_ioctl_set);
 
@@ -862,10 +900,10 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                        if (!br_ioctl_hook)
                                request_module("bridge");
 
-                       down(&br_ioctl_mutex);
+                       mutex_lock(&br_ioctl_mutex);
                        if (br_ioctl_hook) 
                                err = br_ioctl_hook(cmd, argp);
-                       up(&br_ioctl_mutex);
+                       mutex_unlock(&br_ioctl_mutex);
                        break;
                case SIOCGIFVLAN:
                case SIOCSIFVLAN:
@@ -873,10 +911,10 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                        if (!vlan_ioctl_hook)
                                request_module("8021q");
 
-                       down(&vlan_ioctl_mutex);
+                       mutex_lock(&vlan_ioctl_mutex);
                        if (vlan_ioctl_hook)
                                err = vlan_ioctl_hook(argp);
-                       up(&vlan_ioctl_mutex);
+                       mutex_unlock(&vlan_ioctl_mutex);
                        break;
                case SIOCGIFDIVERT:
                case SIOCSIFDIVERT:
@@ -890,9 +928,9 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                                request_module("dlci");
 
                        if (dlci_ioctl_hook) {
-                               down(&dlci_ioctl_mutex);
+                               mutex_lock(&dlci_ioctl_mutex);
                                err = dlci_ioctl_hook(cmd, argp);
-                               up(&dlci_ioctl_mutex);
+                               mutex_unlock(&dlci_ioctl_mutex);
                        }
                        break;
                default:
@@ -1286,19 +1324,17 @@ asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
 {
        struct socket *sock;
        char address[MAX_SOCK_ADDR];
-       int err;
+       int err, fput_needed;
 
-       if((sock = sockfd_lookup(fd,&err))!=NULL)
+       if((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)
        {
                if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) {
                        err = security_socket_bind(sock, (struct sockaddr *)address, addrlen);
-                       if (err) {
-                               sockfd_put(sock);
-                               return err;
-                       }
-                       err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);
+                       if (!err)
+                               err = sock->ops->bind(sock,
+                                       (struct sockaddr *)address, addrlen);
                }
-               sockfd_put(sock);
+               fput_light(sock->file, fput_needed);
        }                       
        return err;
 }
@@ -1315,20 +1351,17 @@ int sysctl_somaxconn = SOMAXCONN;
 asmlinkage long sys_listen(int fd, int backlog)
 {
        struct socket *sock;
-       int err;
+       int err, fput_needed;
        
-       if ((sock = sockfd_lookup(fd, &err)) != NULL) {
+       if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
                if ((unsigned) backlog > sysctl_somaxconn)
                        backlog = sysctl_somaxconn;
 
                err = security_socket_listen(sock, backlog);
-               if (err) {
-                       sockfd_put(sock);
-                       return err;
-               }
+               if (!err)
+                       err = sock->ops->listen(sock, backlog);
 
-               err=sock->ops->listen(sock, backlog);
-               sockfd_put(sock);
+               fput_light(sock->file, fput_needed);
        }
        return err;
 }
@@ -1349,10 +1382,11 @@ asmlinkage long sys_listen(int fd, int backlog)
 asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen)
 {
        struct socket *sock, *newsock;
-       int err, len;
+       struct file *newfile;
+       int err, len, newfd, fput_needed;
        char address[MAX_SOCK_ADDR];
 
-       sock = sockfd_lookup(fd, &err);
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
 
@@ -1369,35 +1403,48 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
         */
        __module_get(newsock->ops->owner);
 
+       newfd = sock_alloc_fd(&newfile);
+       if (unlikely(newfd < 0)) {
+               err = newfd;
+               goto out_release;
+       }
+
+       err = sock_attach_fd(newsock, newfile);
+       if (err < 0)
+               goto out_fd;
+
        err = security_socket_accept(sock, newsock);
        if (err)
-               goto out_release;
+               goto out_fd;
 
        err = sock->ops->accept(sock, newsock, sock->file->f_flags);
        if (err < 0)
-               goto out_release;
+               goto out_fd;
 
        if (upeer_sockaddr) {
                if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) {
                        err = -ECONNABORTED;
-                       goto out_release;
+                       goto out_fd;
                }
                err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
                if (err < 0)
-                       goto out_release;
+                       goto out_fd;
        }
 
        /* File flags are not inherited via accept() unlike another OSes. */
 
-       if ((err = sock_map_fd(newsock)) < 0)
-               goto out_release;
+       fd_install(newfd, newfile);
+       err = newfd;
 
        security_socket_post_accept(sock, newsock);
 
 out_put:
-       sockfd_put(sock);
+       fput_light(sock->file, fput_needed);
 out:
        return err;
+out_fd:
+       put_filp(newfile);
+       put_unused_fd(newfd);
 out_release:
        sock_release(newsock);
        goto out_put;
@@ -1420,9 +1467,9 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl
 {
        struct socket *sock;
        char address[MAX_SOCK_ADDR];
-       int err;
+       int err, fput_needed;
 
-       sock = sockfd_lookup(fd, &err);
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
        err = move_addr_to_kernel(uservaddr, addrlen, address);
@@ -1436,7 +1483,7 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl
        err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
                                 sock->file->f_flags);
 out_put:
-       sockfd_put(sock);
+       fput_light(sock->file, fput_needed);
 out:
        return err;
 }
@@ -1450,9 +1497,9 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _
 {
        struct socket *sock;
        char address[MAX_SOCK_ADDR];
-       int len, err;
+       int len, err, fput_needed;
        
-       sock = sockfd_lookup(fd, &err);
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
 
@@ -1466,7 +1513,7 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _
        err = move_addr_to_user(address, len, usockaddr, usockaddr_len);
 
 out_put:
-       sockfd_put(sock);
+       fput_light(sock->file, fput_needed);
 out:
        return err;
 }
@@ -1480,20 +1527,19 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int _
 {
        struct socket *sock;
        char address[MAX_SOCK_ADDR];
-       int len, err;
+       int len, err, fput_needed;
 
-       if ((sock = sockfd_lookup(fd, &err))!=NULL)
-       {
+       if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
                err = security_socket_getpeername(sock);
                if (err) {
-                       sockfd_put(sock);
+                       fput_light(sock->file, fput_needed);
                        return err;
                }
 
                err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
                if (!err)
                        err=move_addr_to_user(address,len, usockaddr, usockaddr_len);
-               sockfd_put(sock);
+               fput_light(sock->file, fput_needed);
        }
        return err;
 }
@@ -1512,10 +1558,16 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
        int err;
        struct msghdr msg;
        struct iovec iov;
-       
-       sock = sockfd_lookup(fd, &err);
+       int fput_needed;
+       struct file *sock_file;
+
+       sock_file = fget_light(fd, &fput_needed);
+       if (!sock_file)
+               return -EBADF;
+
+       sock = sock_from_file(sock_file, &err);
        if (!sock)
-               goto out;
+               goto out_put;
        iov.iov_base=buff;
        iov.iov_len=len;
        msg.msg_name=NULL;
@@ -1524,8 +1576,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
        msg.msg_control=NULL;
        msg.msg_controllen=0;
        msg.msg_namelen=0;
-       if(addr)
-       {
+       if (addr) {
                err = move_addr_to_kernel(addr, addr_len, address);
                if (err < 0)
                        goto out_put;
@@ -1538,8 +1589,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag
        err = sock_sendmsg(sock, &msg, len);
 
 out_put:               
-       sockfd_put(sock);
-out:
+       fput_light(sock_file, fput_needed);
        return err;
 }
 
@@ -1566,8 +1616,14 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f
        struct msghdr msg;
        char address[MAX_SOCK_ADDR];
        int err,err2;
+       struct file *sock_file;
+       int fput_needed;
 
-       sock = sockfd_lookup(fd, &err);
+       sock_file = fget_light(fd, &fput_needed);
+       if (!sock_file)
+               return -EBADF;
+
+       sock = sock_from_file(sock_file, &err);
        if (!sock)
                goto out;
 
@@ -1589,8 +1645,8 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f
                if(err2<0)
                        err=err2;
        }
-       sockfd_put(sock);                       
 out:
+       fput_light(sock_file, fput_needed);
        return err;
 }
 
@@ -1610,25 +1666,24 @@ asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags
 
 asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen)
 {
-       int err;
+       int err, fput_needed;
        struct socket *sock;
 
        if (optlen < 0)
                return -EINVAL;
                        
-       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL)
        {
                err = security_socket_setsockopt(sock,level,optname);
-               if (err) {
-                       sockfd_put(sock);
-                       return err;
-               }
+               if (err)
+                       goto out_put;
 
                if (level == SOL_SOCKET)
                        err=sock_setsockopt(sock,level,optname,optval,optlen);
                else
                        err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
-               sockfd_put(sock);
+out_put:
+               fput_light(sock->file, fput_needed);
        }
        return err;
 }
@@ -1640,23 +1695,20 @@ asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optv
 
 asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen)
 {
-       int err;
+       int err, fput_needed;
        struct socket *sock;
 
-       if ((sock = sockfd_lookup(fd, &err))!=NULL)
-       {
-               err = security_socket_getsockopt(sock, level, 
-                                                          optname);
-               if (err) {
-                       sockfd_put(sock);
-                       return err;
-               }
+       if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) {
+               err = security_socket_getsockopt(sock, level, optname);
+               if (err)
+                       goto out_put;
 
                if (level == SOL_SOCKET)
                        err=sock_getsockopt(sock,level,optname,optval,optlen);
                else
                        err=sock->ops->getsockopt(sock, level, optname, optval, optlen);
-               sockfd_put(sock);
+out_put:
+               fput_light(sock->file, fput_needed);
        }
        return err;
 }
@@ -1668,19 +1720,15 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optv
 
 asmlinkage long sys_shutdown(int fd, int how)
 {
-       int err;
+       int err, fput_needed;
        struct socket *sock;
 
-       if ((sock = sockfd_lookup(fd, &err))!=NULL)
+       if ((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)
        {
                err = security_socket_shutdown(sock, how);
-               if (err) {
-                       sockfd_put(sock);
-                       return err;
-               }
-                               
-               err=sock->ops->shutdown(sock, how);
-               sockfd_put(sock);
+               if (!err)
+                       err = sock->ops->shutdown(sock, how);
+               fput_light(sock->file, fput_needed);
        }
        return err;
 }
@@ -1709,6 +1757,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
        unsigned char *ctl_buf = ctl;
        struct msghdr msg_sys;
        int err, ctl_len, iov_size, total_len;
+       int fput_needed;
        
        err = -EFAULT;
        if (MSG_CMSG_COMPAT & flags) {
@@ -1717,7 +1766,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
        } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
                return -EFAULT;
 
-       sock = sockfd_lookup(fd, &err);
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock) 
                goto out;
 
@@ -1785,7 +1834,7 @@ out_freeiov:
        if (iov != iovstack)
                sock_kfree_s(sock->sk, iov, iov_size);
 out_put:
-       sockfd_put(sock);
+       fput_light(sock->file, fput_needed);
 out:       
        return err;
 }
@@ -1803,6 +1852,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag
        struct msghdr msg_sys;
        unsigned long cmsg_ptr;
        int err, iov_size, total_len, len;
+       int fput_needed;
 
        /* kernel mode address */
        char addr[MAX_SOCK_ADDR];
@@ -1818,7 +1868,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag
                if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
                        return -EFAULT;
 
-       sock = sockfd_lookup(fd, &err);
+       sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
 
@@ -1885,7 +1935,7 @@ out_freeiov:
        if (iov != iovstack)
                sock_kfree_s(sock->sk, iov, iov_size);
 out_put:
-       sockfd_put(sock);
+       fput_light(sock->file, fput_needed);
 out:
        return err;
 }
index dcaa0c4..0acccfe 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/proc_fs.h>
 #include <linux/net.h>
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 #include <asm/ioctls.h>
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/cache.h>
@@ -532,7 +533,7 @@ void cache_clean_deferred(void *owner)
  */
 
 static DEFINE_SPINLOCK(queue_lock);
-static DECLARE_MUTEX(queue_io_sem);
+static DEFINE_MUTEX(queue_io_mutex);
 
 struct cache_queue {
        struct list_head        list;
@@ -561,7 +562,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
        if (count == 0)
                return 0;
 
-       down(&queue_io_sem); /* protect against multiple concurrent
+       mutex_lock(&queue_io_mutex); /* protect against multiple concurrent
                              * readers on this file */
  again:
        spin_lock(&queue_lock);
@@ -574,7 +575,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
        }
        if (rp->q.list.next == &cd->queue) {
                spin_unlock(&queue_lock);
-               up(&queue_io_sem);
+               mutex_unlock(&queue_io_mutex);
                BUG_ON(rp->offset);
                return 0;
        }
@@ -621,11 +622,11 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
        }
        if (err == -EAGAIN)
                goto again;
-       up(&queue_io_sem);
+       mutex_unlock(&queue_io_mutex);
        return err ? err :  count;
 }
 
-static char write_buf[8192]; /* protected by queue_io_sem */
+static char write_buf[8192]; /* protected by queue_io_mutex */
 
 static ssize_t
 cache_write(struct file *filp, const char __user *buf, size_t count,
@@ -639,10 +640,10 @@ cache_write(struct file *filp, const char __user *buf, size_t count,
        if (count >= sizeof(write_buf))
                return -EINVAL;
 
-       down(&queue_io_sem);
+       mutex_lock(&queue_io_mutex);
 
        if (copy_from_user(write_buf, buf, count)) {
-               up(&queue_io_sem);
+               mutex_unlock(&queue_io_mutex);
                return -EFAULT;
        }
        write_buf[count] = '\0';
@@ -651,7 +652,7 @@ cache_write(struct file *filp, const char __user *buf, size_t count,
        else
                err = -EINVAL;
 
-       up(&queue_io_sem);
+       mutex_unlock(&queue_io_mutex);
        return err ? err : count;
 }
 
index e838d04..dff0779 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/xprt.h>
@@ -62,7 +63,7 @@ static LIST_HEAD(all_tasks);
 /*
  * rpciod-related stuff
  */
-static DECLARE_MUTEX(rpciod_sema);
+static DEFINE_MUTEX(rpciod_mutex);
 static unsigned int            rpciod_users;
 static struct workqueue_struct *rpciod_workqueue;
 
@@ -1047,7 +1048,7 @@ rpciod_up(void)
        struct workqueue_struct *wq;
        int error = 0;
 
-       down(&rpciod_sema);
+       mutex_lock(&rpciod_mutex);
        dprintk("rpciod_up: users %d\n", rpciod_users);
        rpciod_users++;
        if (rpciod_workqueue)
@@ -1070,14 +1071,14 @@ rpciod_up(void)
        rpciod_workqueue = wq;
        error = 0;
 out:
-       up(&rpciod_sema);
+       mutex_unlock(&rpciod_mutex);
        return error;
 }
 
 void
 rpciod_down(void)
 {
-       down(&rpciod_sema);
+       mutex_lock(&rpciod_mutex);
        dprintk("rpciod_down sema %d\n", rpciod_users);
        if (rpciod_users) {
                if (--rpciod_users)
@@ -1094,7 +1095,7 @@ rpciod_down(void)
        destroy_workqueue(rpciod_workqueue);
        rpciod_workqueue = NULL;
  out:
-       up(&rpciod_sema);
+       mutex_unlock(&rpciod_mutex);
 }
 
 #ifdef RPC_DEBUG
index 5058062..a27905a 100644 (file)
@@ -1296,13 +1296,13 @@ svc_send(struct svc_rqst *rqstp)
                xb->page_len +
                xb->tail[0].iov_len;
 
-       /* Grab svsk->sk_sem to serialize outgoing data. */
-       down(&svsk->sk_sem);
+       /* Grab svsk->sk_mutex to serialize outgoing data. */
+       mutex_lock(&svsk->sk_mutex);
        if (test_bit(SK_DEAD, &svsk->sk_flags))
                len = -ENOTCONN;
        else
                len = svsk->sk_sendto(rqstp);
-       up(&svsk->sk_sem);
+       mutex_unlock(&svsk->sk_mutex);
        svc_sock_release(rqstp);
 
        if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
@@ -1351,7 +1351,7 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
        svsk->sk_lastrecv = get_seconds();
        INIT_LIST_HEAD(&svsk->sk_deferred);
        INIT_LIST_HEAD(&svsk->sk_ready);
-       sema_init(&svsk->sk_sem, 1);
+       mutex_init(&svsk->sk_mutex);
 
        /* Initialize the socket */
        if (sock->type == SOCK_DGRAM)
index a7b04f3..2c4ecbe 100644 (file)
@@ -107,22 +107,22 @@ static spinlock_t bc_lock = SPIN_LOCK_UNLOCKED;
 char tipc_bclink_name[] = "multicast-link";
 
 
-static inline u32 buf_seqno(struct sk_buff *buf)
+static u32 buf_seqno(struct sk_buff *buf)
 {
        return msg_seqno(buf_msg(buf));
 } 
 
-static inline u32 bcbuf_acks(struct sk_buff *buf)
+static u32 bcbuf_acks(struct sk_buff *buf)
 {
        return (u32)(unsigned long)TIPC_SKB_CB(buf)->handle;
 }
 
-static inline void bcbuf_set_acks(struct sk_buff *buf, u32 acks)
+static void bcbuf_set_acks(struct sk_buff *buf, u32 acks)
 {
        TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)acks;
 }
 
-static inline void bcbuf_decr_acks(struct sk_buff *buf)
+static void bcbuf_decr_acks(struct sk_buff *buf)
 {
        bcbuf_set_acks(buf, bcbuf_acks(buf) - 1);
 }
@@ -134,7 +134,7 @@ static inline void bcbuf_decr_acks(struct sk_buff *buf)
  * Called with 'node' locked, bc_lock unlocked
  */
 
-static inline void bclink_set_gap(struct node *n_ptr)
+static void bclink_set_gap(struct node *n_ptr)
 {
        struct sk_buff *buf = n_ptr->bclink.deferred_head;
 
@@ -154,7 +154,7 @@ static inline void bclink_set_gap(struct node *n_ptr)
  *       distribute NACKs, but tries to use the same spacing (divide by 16). 
  */
 
-static inline int bclink_ack_allowed(u32 n)
+static int bclink_ack_allowed(u32 n)
 {
        return((n % TIPC_MIN_LINK_WIN) == tipc_own_tag);
 }
@@ -271,7 +271,7 @@ static void bclink_send_nack(struct node *n_ptr)
                msg_set_bcgap_to(msg, n_ptr->bclink.gap_to);
                msg_set_bcast_tag(msg, tipc_own_tag);
 
-               if (tipc_bearer_send(&bcbearer->bearer, buf, 0)) {
+               if (tipc_bearer_send(&bcbearer->bearer, buf, NULL)) {
                        bcl->stats.sent_nacks++;
                        buf_discard(buf);
                } else {
@@ -314,7 +314,7 @@ void tipc_bclink_check_gap(struct node *n_ptr, u32 last_sent)
  * Only tipc_net_lock set.
  */
 
-void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
+static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
 {
        struct node *n_ptr = tipc_node_find(dest);
        u32 my_after, my_to;
@@ -425,9 +425,9 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
                                              msg_bcgap_to(msg));
                } else {
                        tipc_bclink_peek_nack(msg_destnode(msg),
-                                        msg_bcast_tag(msg),
-                                        msg_bcgap_after(msg),
-                                        msg_bcgap_to(msg));
+                                             msg_bcast_tag(msg),
+                                             msg_bcgap_after(msg),
+                                             msg_bcgap_to(msg));
                }
                buf_discard(buf);
                return;
@@ -525,16 +525,18 @@ u32 tipc_bclink_acks_missing(struct node *n_ptr)
  * Returns 0 if packet sent successfully, non-zero if not
  */
 
-int tipc_bcbearer_send(struct sk_buff *buf,
-                      struct tipc_bearer *unused1,
-                      struct tipc_media_addr *unused2)
+static int tipc_bcbearer_send(struct sk_buff *buf,
+                             struct tipc_bearer *unused1,
+                             struct tipc_media_addr *unused2)
 {
        static int send_count = 0;
 
-       struct node_map remains;
-       struct node_map remains_new;
+       struct node_map *remains;
+       struct node_map *remains_new;
+       struct node_map *remains_tmp;
        int bp_index;
        int swap_time;
+       int err;
 
        /* Prepare buffer for broadcasting (if first time trying to send it) */
 
@@ -555,7 +557,9 @@ int tipc_bcbearer_send(struct sk_buff *buf,
 
        /* Send buffer over bearers until all targets reached */
        
-       remains = tipc_cltr_bcast_nodes;
+       remains = kmalloc(sizeof(struct node_map), GFP_ATOMIC);
+       remains_new = kmalloc(sizeof(struct node_map), GFP_ATOMIC);
+       *remains = tipc_cltr_bcast_nodes;
 
        for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
                struct bearer *p = bcbearer->bpairs[bp_index].primary;
@@ -564,8 +568,8 @@ int tipc_bcbearer_send(struct sk_buff *buf,
                if (!p)
                        break;  /* no more bearers to try */
 
-               tipc_nmap_diff(&remains, &p->nodes, &remains_new);
-               if (remains_new.count == remains.count)
+               tipc_nmap_diff(remains, &p->nodes, remains_new);
+               if (remains_new->count == remains->count)
                        continue;       /* bearer pair doesn't add anything */
 
                if (!p->publ.blocked &&
@@ -583,17 +587,27 @@ swap:
                bcbearer->bpairs[bp_index].primary = s;
                bcbearer->bpairs[bp_index].secondary = p;
 update:
-               if (remains_new.count == 0)
-                       return TIPC_OK;
+               if (remains_new->count == 0) {
+                       err = TIPC_OK;
+                       goto out;
+               }
 
+               /* swap map */
+               remains_tmp = remains;
                remains = remains_new;
+               remains_new = remains_tmp;
        }
        
        /* Unable to reach all targets */
 
        bcbearer->bearer.publ.blocked = 1;
        bcl->stats.bearer_congs++;
-       return ~TIPC_OK;
+       err = ~TIPC_OK;
+
+ out:
+       kfree(remains_new);
+       kfree(remains);
+       return err;
 }
 
 /**
index 64dcb0f..e213a8e 100644 (file)
 
 #define MAX_ADDR_STR 32
 
-static struct media *media_list = 0;
+static struct media *media_list = NULL;
 static u32 media_count = 0;
 
-struct bearer *tipc_bearers = 0;
+struct bearer *tipc_bearers = NULL;
 
 /**
  * media_name_valid - validate media name
@@ -79,7 +79,7 @@ static struct media *media_find(const char *name)
                if (!strcmp(m_ptr->name, name))
                        return m_ptr;
        }
-       return 0;
+       return NULL;
 }
 
 /**
@@ -287,7 +287,7 @@ static struct bearer *bearer_find(const char *name)
                if (b_ptr->active && (!strcmp(b_ptr->publ.name, name)))
                        return b_ptr;
        }
-       return 0;
+       return NULL;
 }
 
 /**
@@ -307,7 +307,7 @@ struct bearer *tipc_bearer_find_interface(const char *if_name)
                if (!strcmp(b_if_name, if_name))
                        return b_ptr;
        }
-       return 0;
+       return NULL;
 }
 
 /**
@@ -569,7 +569,7 @@ failed:
 
 int tipc_block_bearer(const char *name)
 {
-       struct bearer *b_ptr = 0;
+       struct bearer *b_ptr = NULL;
        struct link *l_ptr;
        struct link *temp_l_ptr;
 
@@ -666,8 +666,8 @@ int tipc_bearer_init(void)
        } else {
                kfree(tipc_bearers);
                kfree(media_list);
-               tipc_bearers = 0;
-               media_list = 0;
+               tipc_bearers = NULL;
+               media_list = NULL;
                res = -ENOMEM;
        }
        write_unlock_bh(&tipc_net_lock);
@@ -691,8 +691,8 @@ void tipc_bearer_stop(void)
        }
        kfree(tipc_bearers);
        kfree(media_list);
-       tipc_bearers = 0;
-       media_list = 0;
+       tipc_bearers = NULL;
+       media_list = NULL;
        media_count = 0;
 }
 
index ab974ca..1aed815 100644 (file)
 #include "msg.h"
 #include "bearer.h"
 
-void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, 
-                        u32 lower, u32 upper);
-struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest);
+static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
+                               u32 lower, u32 upper);
+static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest);
 
-struct node **tipc_local_nodes = 0;
+struct node **tipc_local_nodes = NULL;
 struct node_map tipc_cltr_bcast_nodes = {0,{0,}};
 u32 tipc_highest_allowed_slave = 0;
 
@@ -61,7 +61,7 @@ struct cluster *tipc_cltr_create(u32 addr)
 
        c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC);
        if (c_ptr == NULL)
-               return 0;
+               return NULL;
        memset(c_ptr, 0, sizeof(*c_ptr));
 
        c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
@@ -73,7 +73,7 @@ struct cluster *tipc_cltr_create(u32 addr)
        c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC);
        if (c_ptr->nodes == NULL) {
                kfree(c_ptr);
-               return 0;
+               return NULL;
        }
        memset(c_ptr->nodes, 0, alloc);  
        if (in_own_cluster(addr))
@@ -91,7 +91,7 @@ struct cluster *tipc_cltr_create(u32 addr)
        }
        else {
                kfree(c_ptr);
-               c_ptr = 0;
+               c_ptr = NULL;
        }
 
        return c_ptr;
@@ -204,7 +204,7 @@ struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector)
 
        assert(!in_own_cluster(c_ptr->addr));
        if (!c_ptr->highest_node)
-               return 0;
+               return NULL;
 
        /* Start entry must be random */
        while (mask > c_ptr->highest_node) {
@@ -222,14 +222,14 @@ struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector)
                if (tipc_node_has_active_links(c_ptr->nodes[n_num]))
                        return c_ptr->nodes[n_num];
        }
-       return 0;
+       return NULL;
 }
 
 /*
  *    Routing table management: See description in node.c
  */
 
-struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
+static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
 {
        u32 size = INT_H_SIZE + data_size;
        struct sk_buff *buf = buf_acquire(size);
@@ -495,7 +495,7 @@ void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router)
  * tipc_cltr_multicast - multicast message to local nodes 
  */
 
-void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, 
+static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
                         u32 lower, u32 upper)
 {
        struct sk_buff *buf_copy;
index 9963642..1b4cd30 100644 (file)
@@ -86,7 +86,7 @@ static inline struct cluster *tipc_cltr_find(u32 addr)
 
        if (z_ptr)
                return z_ptr->clusters[1];
-       return 0;
+       return NULL;
 }
 
 #endif
index 3c8e674..48b5de2 100644 (file)
@@ -683,11 +683,11 @@ int tipc_cfg_init(void)
        memset(&mng, 0, sizeof(mng));
        INIT_LIST_HEAD(&mng.link_subscribers);
 
-       res = tipc_attach(&mng.user_ref, 0, 0);
+       res = tipc_attach(&mng.user_ref, NULL, NULL);
        if (res)
                goto failed;
 
-       res = tipc_createport(mng.user_ref, 0, TIPC_CRITICAL_IMPORTANCE,
+       res = tipc_createport(mng.user_ref, NULL, TIPC_CRITICAL_IMPORTANCE,
                              NULL, NULL, NULL,
                              NULL, cfg_named_msg_event, NULL,
                              NULL, &mng.port_ref);
index 4f4beef..26ef95d 100644 (file)
@@ -81,7 +81,7 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 sz)
 
        pb->crs = pb->buf = raw;
        pb->size = sz;
-       pb->next = 0;
+       pb->next = NULL;
        pb->buf[0] = 0;
        pb->buf[sz-1] = ~0;
 }
@@ -216,7 +216,7 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
                         }
                 }
                pb_next = pb->next;
-               pb->next = 0;
+               pb->next = NULL;
                pb = pb_next;
        }
        spin_unlock_bh(&print_lock);
index 53ba463..9260138 100644 (file)
@@ -110,10 +110,10 @@ void tipc_disc_link_event(u32 addr, char *name, int up)
  * @b_ptr: ptr to bearer issuing message
  */
 
-struct sk_buff *tipc_disc_init_msg(u32 type,
-                                  u32 req_links,
-                                  u32 dest_domain,
-                                  struct bearer *b_ptr)
+static struct sk_buff *tipc_disc_init_msg(u32 type,
+                                         u32 req_links,
+                                         u32 dest_domain,
+                                         struct bearer *b_ptr)
 {
        struct sk_buff *buf = buf_acquire(DSC_H_SIZE);
        struct tipc_msg *msg;
index 1f8d83b..7a25278 100644 (file)
@@ -169,7 +169,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr)
 
 static void disable_bearer(struct tipc_bearer *tb_ptr)
 {
-       ((struct eth_bearer *)tb_ptr->usr_handle)->bearer = 0;
+       ((struct eth_bearer *)tb_ptr->usr_handle)->bearer = NULL;
 }
 
 /**
@@ -285,7 +285,7 @@ void tipc_eth_media_stop(void)
        for (i = 0; i < MAX_ETH_BEARERS ; i++) {
                if (eth_bearers[i].bearer) {
                        eth_bearers[i].bearer->blocked = 1;
-                       eth_bearers[i].bearer = 0;
+                       eth_bearers[i].bearer = NULL;
                }
                if (eth_bearers[i].dev) {
                        dev_remove_pack(&eth_bearers[i].tipc_packet_type);
index 511872a..910b37e 100644 (file)
@@ -157,13 +157,13 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
        } \
 } while (0)
 
-static inline void dbg_print_link(struct link *l_ptr, const char *str)
+static void dbg_print_link(struct link *l_ptr, const char *str)
 {
        if (DBG_OUTPUT)
                link_print(l_ptr, DBG_OUTPUT, str);
 }
 
-static inline void dbg_print_buf_chain(struct sk_buff *root_buf)
+static void dbg_print_buf_chain(struct sk_buff *root_buf)
 {
        if (DBG_OUTPUT) {
                struct sk_buff *buf = root_buf;
@@ -176,50 +176,50 @@ static inline void dbg_print_buf_chain(struct sk_buff *root_buf)
 }
 
 /*
- *  Simple inlined link routines
+ *  Simple link routines
  */
 
-static inline unsigned int align(unsigned int i)
+static unsigned int align(unsigned int i)
 {
        return (i + 3) & ~3u;
 }
 
-static inline int link_working_working(struct link *l_ptr)
+static int link_working_working(struct link *l_ptr)
 {
        return (l_ptr->state == WORKING_WORKING);
 }
 
-static inline int link_working_unknown(struct link *l_ptr)
+static int link_working_unknown(struct link *l_ptr)
 {
        return (l_ptr->state == WORKING_UNKNOWN);
 }
 
-static inline int link_reset_unknown(struct link *l_ptr)
+static int link_reset_unknown(struct link *l_ptr)
 {
        return (l_ptr->state == RESET_UNKNOWN);
 }
 
-static inline int link_reset_reset(struct link *l_ptr)
+static int link_reset_reset(struct link *l_ptr)
 {
        return (l_ptr->state == RESET_RESET);
 }
 
-static inline int link_blocked(struct link *l_ptr)
+static int link_blocked(struct link *l_ptr)
 {
        return (l_ptr->exp_msg_count || l_ptr->blocked);
 }
 
-static inline int link_congested(struct link *l_ptr)
+static int link_congested(struct link *l_ptr)
 {
        return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
 }
 
-static inline u32 link_max_pkt(struct link *l_ptr)
+static u32 link_max_pkt(struct link *l_ptr)
 {
        return l_ptr->max_pkt;
 }
 
-static inline void link_init_max_pkt(struct link *l_ptr)
+static void link_init_max_pkt(struct link *l_ptr)
 {
        u32 max_pkt;
        
@@ -236,20 +236,20 @@ static inline void link_init_max_pkt(struct link *l_ptr)
         l_ptr->max_pkt_probes = 0;
 }
 
-static inline u32 link_next_sent(struct link *l_ptr)
+static u32 link_next_sent(struct link *l_ptr)
 {
        if (l_ptr->next_out)
                return msg_seqno(buf_msg(l_ptr->next_out));
        return mod(l_ptr->next_out_no);
 }
 
-static inline u32 link_last_sent(struct link *l_ptr)
+static u32 link_last_sent(struct link *l_ptr)
 {
        return mod(link_next_sent(l_ptr) - 1);
 }
 
 /*
- *  Simple non-inlined link routines (i.e. referenced outside this file)
+ *  Simple non-static link routines (i.e. referenced outside this file)
  */
 
 int tipc_link_is_up(struct link *l_ptr)
@@ -396,7 +396,7 @@ static void link_timeout(struct link *l_ptr)
        tipc_node_unlock(l_ptr->owner);
 }
 
-static inline void link_set_timer(struct link *l_ptr, u32 time)
+static void link_set_timer(struct link *l_ptr, u32 time)
 {
        k_start_timer(&l_ptr->timer, time);
 }
@@ -573,7 +573,7 @@ void tipc_link_wakeup_ports(struct link *l_ptr, int all)
                if (win <= 0)
                        break;
                list_del_init(&p_ptr->wait_list);
-               p_ptr->congested_link = 0;
+               p_ptr->congested_link = NULL;
                assert(p_ptr->wakeup);
                spin_lock_bh(p_ptr->publ.lock);
                p_ptr->publ.congested = 0;
@@ -1004,9 +1004,9 @@ static int link_bundle_buf(struct link *l_ptr,
        return 1;
 }
 
-static inline void link_add_to_outqueue(struct link *l_ptr, 
-                                       struct sk_buff *buf, 
-                                       struct tipc_msg *msg)
+static void link_add_to_outqueue(struct link *l_ptr,
+                                struct sk_buff *buf,
+                                struct tipc_msg *msg)
 {
        u32 ack = mod(l_ptr->next_in_no - 1);
        u32 seqno = mod(l_ptr->next_out_no++);
@@ -1156,8 +1156,8 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
  * Link is locked. Returns user data length.
  */
 
-static inline int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
-                                    u32 *used_max_pkt)
+static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
+                             u32 *used_max_pkt)
 {
        struct tipc_msg *msg = buf_msg(buf);
        int res = msg_data_sz(msg);
@@ -1355,7 +1355,7 @@ again:
        fragm_crs = 0;
        fragm_rest = 0;
        sect_rest = 0;
-       sect_crs = 0;
+       sect_crs = NULL;
        curr_sect = -1;
 
        /* Prepare reusable fragment header: */
@@ -1549,7 +1549,7 @@ u32 tipc_link_push_packet(struct link *l_ptr)
                        msg_dbg(buf_msg(buf), ">DEF-PROT>");
                        l_ptr->unacked_window = 0;
                        buf_discard(buf);
-                       l_ptr->proto_msg_queue = 0;
+                       l_ptr->proto_msg_queue = NULL;
                        return TIPC_OK;
                } else {
                        msg_dbg(buf_msg(buf), "|>DEF-PROT>");
@@ -1860,7 +1860,7 @@ u32 tipc_link_defer_pkt(struct sk_buff **head,
                        struct sk_buff **tail,
                        struct sk_buff *buf)
 {
-       struct sk_buff *prev = 0;
+       struct sk_buff *prev = NULL;
        struct sk_buff *crs = *head;
        u32 seq_no = msg_seqno(buf_msg(buf));
 
@@ -1953,7 +1953,7 @@ static void link_handle_out_of_seq_msg(struct link *l_ptr,
 void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
                              u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
 {
-       struct sk_buff *buf = 0;
+       struct sk_buff *buf = NULL;
        struct tipc_msg *msg = l_ptr->pmsg;
         u32 msg_size = sizeof(l_ptr->proto_msg);
 
@@ -2426,7 +2426,7 @@ static int link_recv_changeover_msg(struct link **l_ptr,
                }
        }
 exit:
-       *buf = 0;
+       *buf = NULL;
        buf_discard(tunnel_buf);
        return 0;
 }
@@ -2539,42 +2539,37 @@ exit:
  * pending message. This makes dynamic memory allocation unecessary.
  */
 
-static inline u32 get_long_msg_seqno(struct sk_buff *buf)
-{
-       return msg_seqno(buf_msg(buf));
-}
-
-static inline void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
+static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
 {
        msg_set_seqno(buf_msg(buf), seqno);
 }
 
-static inline u32 get_fragm_size(struct sk_buff *buf)
+static u32 get_fragm_size(struct sk_buff *buf)
 {
        return msg_ack(buf_msg(buf));
 }
 
-static inline void set_fragm_size(struct sk_buff *buf, u32 sz)
+static void set_fragm_size(struct sk_buff *buf, u32 sz)
 {
        msg_set_ack(buf_msg(buf), sz);
 }
 
-static inline u32 get_expected_frags(struct sk_buff *buf)
+static u32 get_expected_frags(struct sk_buff *buf)
 {
        return msg_bcast_ack(buf_msg(buf));
 }
 
-static inline void set_expected_frags(struct sk_buff *buf, u32 exp)
+static void set_expected_frags(struct sk_buff *buf, u32 exp)
 {
        msg_set_bcast_ack(buf_msg(buf), exp);
 }
 
-static inline u32 get_timer_cnt(struct sk_buff *buf)
+static u32 get_timer_cnt(struct sk_buff *buf)
 {
        return msg_reroute_cnt(buf_msg(buf));
 }
 
-static inline void incr_timer_cnt(struct sk_buff *buf)
+static void incr_timer_cnt(struct sk_buff *buf)
 {
        msg_incr_reroute_cnt(buf_msg(buf));
 }
@@ -2586,13 +2581,13 @@ static inline void incr_timer_cnt(struct sk_buff *buf)
 int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, 
                            struct tipc_msg **m)
 {
-       struct sk_buff *prev = 0;
+       struct sk_buff *prev = NULL;
        struct sk_buff *fbuf = *fb;
        struct tipc_msg *fragm = buf_msg(fbuf);
        struct sk_buff *pbuf = *pending;
        u32 long_msg_seq_no = msg_long_msgno(fragm);
 
-       *fb = 0;
+       *fb = NULL;
        msg_dbg(fragm,"FRG<REC<");
 
        /* Is there an incomplete message waiting for this fragment? */
@@ -2670,8 +2665,8 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
 
 static void link_check_defragm_bufs(struct link *l_ptr)
 {
-       struct sk_buff *prev = 0;
-       struct sk_buff *next = 0;
+       struct sk_buff *prev = NULL;
+       struct sk_buff *next = NULL;
        struct sk_buff *buf = l_ptr->defragm_buf;
 
        if (!buf)
@@ -2750,19 +2745,19 @@ static struct link *link_find_link(const char *name, struct node **node)
        struct link *l_ptr; 
 
        if (!link_name_validate(name, &link_name_parts))
-               return 0;
+               return NULL;
 
        b_ptr = tipc_bearer_find_interface(link_name_parts.if_local);
        if (!b_ptr)
-               return 0;
+               return NULL;
 
        *node = tipc_node_find(link_name_parts.addr_peer); 
        if (!*node)
-               return 0;
+               return NULL;
 
        l_ptr = (*node)->links[b_ptr->identity];
        if (!l_ptr || strcmp(l_ptr->name, name))
-               return 0;
+               return NULL;
 
        return l_ptr;
 }
index 830f909..953307a 100644 (file)
@@ -168,8 +168,8 @@ void tipc_named_withdraw(struct publication *publ)
 void tipc_named_node_up(unsigned long node)
 {
        struct publication *publ;
-       struct distr_item *item = 0;
-       struct sk_buff *buf = 0;
+       struct distr_item *item = NULL;
+       struct sk_buff *buf = NULL;
        u32 left = 0;
        u32 rest;
        u32 max_item_buf;
@@ -200,7 +200,7 @@ void tipc_named_node_up(unsigned long node)
                            "<%u.%u.%u>\n", tipc_zone(node), 
                            tipc_cluster(node), tipc_node(node));
                        tipc_link_send(buf, node, node);
-                       buf = 0;
+                       buf = NULL;
                }
        }
 exit:
index 3f4b23b..d129422 100644 (file)
@@ -46,7 +46,7 @@
 #include "cluster.h"
 #include "bcast.h"
 
-int tipc_nametbl_size = 1024;          /* must be a power of 2 */
+static int tipc_nametbl_size = 1024;           /* must be a power of 2 */
 
 /**
  * struct sub_seq - container for all published instances of a name sequence
@@ -104,7 +104,7 @@ static atomic_t rsv_publ_ok = ATOMIC_INIT(0);
 rwlock_t tipc_nametbl_lock = RW_LOCK_UNLOCKED;
 
 
-static inline int hash(int x)
+static int hash(int x)
 {
        return(x & (tipc_nametbl_size - 1));
 }
@@ -121,7 +121,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper,
                (struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC);
        if (publ == NULL) {
                warn("Memory squeeze; failed to create publication\n");
-               return 0;
+               return NULL;
        }
 
        memset(publ, 0, sizeof(*publ));
@@ -142,7 +142,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper,
  * tipc_subseq_alloc - allocate a specified number of sub-sequence structures
  */
 
-struct sub_seq *tipc_subseq_alloc(u32 cnt)
+static struct sub_seq *tipc_subseq_alloc(u32 cnt)
 {
        u32 sz = cnt * sizeof(struct sub_seq);
        struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC);
@@ -158,7 +158,7 @@ struct sub_seq *tipc_subseq_alloc(u32 cnt)
  * Allocates a single sub-sequence structure and sets it to all 0's.
  */
 
-struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
+static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
 {
        struct name_seq *nseq = 
                (struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC);
@@ -168,7 +168,7 @@ struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
                warn("Memory squeeze; failed to create name sequence\n");
                kfree(nseq);
                kfree(sseq);
-               return 0;
+               return NULL;
        }
 
        memset(nseq, 0, sizeof(*nseq));
@@ -190,8 +190,8 @@ struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
  * Very time-critical, so binary searches through sub-sequence array.
  */
 
-static inline struct sub_seq *nameseq_find_subseq(struct name_seq *nseq, 
-                                                 u32 instance)
+static struct sub_seq *nameseq_find_subseq(struct name_seq *nseq,
+                                          u32 instance)
 {
        struct sub_seq *sseqs = nseq->sseqs;
        int low = 0;
@@ -207,7 +207,7 @@ static inline struct sub_seq *nameseq_find_subseq(struct name_seq *nseq,
                else
                        return &sseqs[mid];
        }
-       return 0;
+       return NULL;
 }
 
 /**
@@ -243,9 +243,9 @@ static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
  * tipc_nameseq_insert_publ - 
  */
 
-struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
-                                       u32 type, u32 lower, u32 upper,
-                                       u32 scope, u32 node, u32 port, u32 key)
+static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
+                                                   u32 type, u32 lower, u32 upper,
+                                                   u32 scope, u32 node, u32 port, u32 key)
 {
        struct subscription *s;
        struct subscription *st;
@@ -263,7 +263,7 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
 
                if ((sseq->lower != lower) || (sseq->upper != upper)) {
                        warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
-                       return 0;
+                       return NULL;
                }
        } else {
                u32 inspos;
@@ -278,7 +278,7 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
                if ((inspos < nseq->first_free) &&
                    (upper >= nseq->sseqs[inspos].lower)) {
                        warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
-                       return 0;
+                       return NULL;
                }
 
                /* Ensure there is space for new sub-sequence */
@@ -294,7 +294,7 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
                                nseq->alloc *= 2;
                        } else {
                                warn("Memory squeeze; failed to create sub-sequence\n");
-                               return 0;
+                               return NULL;
                        }
                }
                dbg("Have %u sseqs for type %u\n", nseq->alloc, type);
@@ -319,7 +319,7 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
 
        publ = publ_create(type, lower, upper, scope, node, port, key);
        if (!publ)
-               return 0;
+               return NULL;
        dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n",
            publ, node, publ->node, publ->subscr.node);
 
@@ -369,8 +369,8 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
  * tipc_nameseq_remove_publ -
  */
 
-struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
-                                            u32 node, u32 ref, u32 key)
+static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
+                                                   u32 node, u32 ref, u32 key)
 {
        struct publication *publ;
        struct publication *prev;
@@ -394,7 +394,7 @@ struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
                            i, &nseq->sseqs[i], nseq->sseqs[i].lower,
                            nseq->sseqs[i].upper);
                }
-               return 0;
+               return NULL;
        }
        dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n",
            nseq, sseq, nseq->type, inst, key);
@@ -413,7 +413,7 @@ struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
                prev->zone_list_next = publ->zone_list_next;
                sseq->zone_list = publ->zone_list_next;
        } else {
-               sseq->zone_list = 0;
+               sseq->zone_list = NULL;
        }
 
        if (in_own_cluster(node)) {
@@ -431,7 +431,7 @@ struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
                        prev->cluster_list_next = publ->cluster_list_next;
                        sseq->cluster_list = publ->cluster_list_next;
                } else {
-                       sseq->cluster_list = 0;
+                       sseq->cluster_list = NULL;
                }
        }
 
@@ -450,7 +450,7 @@ struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
                        prev->node_list_next = publ->node_list_next;
                        sseq->node_list = publ->node_list_next;
                } else {
-                       sseq->node_list = 0;
+                       sseq->node_list = NULL;
                }
        }
        assert(!publ->node || (publ->node == node));
@@ -535,7 +535,7 @@ static struct name_seq *nametbl_find_seq(u32 type)
                }
        }
 
-       return 0;
+       return NULL;
 };
 
 struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
@@ -547,7 +547,7 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
        if (lower > upper) {
                warn("Failed to publish illegal <%u,%u,%u>\n",
                     type, lower, upper);
-               return 0;
+               return NULL;
        }
 
        dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node);
@@ -556,7 +556,7 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
                dbg("tipc_nametbl_insert_publ: created %x\n", seq);
        }
        if (!seq)
-               return 0;
+               return NULL;
 
        assert(seq->type == type);
        return tipc_nameseq_insert_publ(seq, type, lower, upper,
@@ -570,7 +570,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
        struct name_seq *seq = nametbl_find_seq(type);
 
        if (!seq)
-               return 0;
+               return NULL;
 
        dbg("Withdrawing <%u,%u> from %x\n", type, lower, node);
        publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
@@ -594,7 +594,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
 u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
 {
        struct sub_seq *sseq;
-       struct publication *publ = 0;
+       struct publication *publ = NULL;
        struct name_seq *seq;
        u32 ref;
 
@@ -740,12 +740,12 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
        if (table.local_publ_count >= tipc_max_publications) {
                warn("Failed publish: max %u local publication\n", 
                     tipc_max_publications);
-               return 0;
+               return NULL;
        }
        if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) {
                warn("Failed to publish reserved name <%u,%u,%u>\n",
                     type, lower, upper);
-               return 0;
+               return NULL;
        }
 
        write_lock_bh(&tipc_nametbl_lock);
@@ -983,6 +983,7 @@ static void nametbl_list(struct print_buf *buf, u32 depth_info,
        }
 }
 
+#if 0
 void tipc_nametbl_print(struct print_buf *buf, const char *str)
 {
        tipc_printf(buf, str);
@@ -990,6 +991,7 @@ void tipc_nametbl_print(struct print_buf *buf, const char *str)
        nametbl_list(buf, 0, 0, 0, 0);
        read_unlock_bh(&tipc_nametbl_lock);
 }
+#endif
 
 #define MAX_NAME_TBL_QUERY 32768
 
@@ -1023,10 +1025,12 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
        return buf;
 }
 
+#if 0
 void tipc_nametbl_dump(void)
 {
        nametbl_list(TIPC_CONS, 0, 0, 0, 0);
 }
+#endif
 
 int tipc_nametbl_init(void)
 {
index 074891a..f7c8223 100644 (file)
 */
 
 rwlock_t tipc_net_lock = RW_LOCK_UNLOCKED;
-struct network tipc_net = { 0 };
+struct network tipc_net = { NULL };
 
 struct node *tipc_net_select_remote_node(u32 addr, u32 ref) 
 {
@@ -128,13 +128,14 @@ u32 tipc_net_select_router(u32 addr, u32 ref)
        return tipc_zone_select_router(tipc_net.zones[tipc_zone(addr)], addr, ref);
 }
 
-
+#if 0
 u32 tipc_net_next_node(u32 a)
 {
        if (tipc_net.zones[tipc_zone(a)])
                return tipc_zone_next_node(a);
        return 0;
 }
+#endif
 
 void tipc_net_remove_as_router(u32 router)
 {
@@ -181,7 +182,7 @@ static void net_stop(void)
                tipc_zone_delete(tipc_net.zones[z_num]);
        }
        kfree(tipc_net.zones);
-       tipc_net.zones = 0;
+       tipc_net.zones = NULL;
 }
 
 static void net_route_named_msg(struct sk_buff *buf)
index 6d65010..0d5db06 100644 (file)
@@ -155,7 +155,7 @@ static void node_select_active_links(struct node *n_ptr)
        u32 i;
        u32 highest_prio = 0;
 
-        active[0] = active[1] = 0;
+        active[0] = active[1] = NULL;
 
        for (i = 0; i < MAX_BEARERS; i++) {
                 struct link *l_ptr = n_ptr->links[i];
@@ -214,7 +214,7 @@ int tipc_node_has_redundant_links(struct node *n_ptr)
                (n_ptr->active_links[0] != n_ptr->active_links[1]));
 }
 
-int tipc_node_has_active_routes(struct node *n_ptr)
+static int tipc_node_has_active_routes(struct node *n_ptr)
 {
        return (n_ptr && (n_ptr->last_router >= 0));
 }
@@ -240,7 +240,7 @@ struct node *tipc_node_attach_link(struct link *l_ptr)
 
                         err("Attempt to create third link to %s\n",
                            addr_string_fill(addr_string, n_ptr->addr));
-                        return 0;
+                        return NULL;
                 }
 
                 if (!n_ptr->links[bearer_id]) {
@@ -253,12 +253,12 @@ struct node *tipc_node_attach_link(struct link *l_ptr)
                     l_ptr->b_ptr->publ.name, 
                    addr_string_fill(addr_string, l_ptr->addr));
         }
-       return 0;
+       return NULL;
 }
 
 void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr)
 {
-       n_ptr->links[l_ptr->b_ptr->identity] = 0;
+       n_ptr->links[l_ptr->b_ptr->identity] = NULL;
        tipc_net.zones[tipc_zone(l_ptr->addr)]->links--;
        n_ptr->link_cnt--;
 }
@@ -424,7 +424,7 @@ static void node_lost_contact(struct node *n_ptr)
 
        /* Notify subscribers */
        list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
-                ns->node = 0;
+                ns->node = NULL;
                list_del_init(&ns->nodesub_list);
                tipc_k_signal((Handler)ns->handle_node_down,
                              (unsigned long)ns->usr_handle);
@@ -443,7 +443,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
        u32 router_addr;
 
         if (!tipc_addr_domain_valid(addr))
-                return 0;
+                return NULL;
 
        /* Look for direct link to destination processsor */
        n_ptr = tipc_node_find(addr);
@@ -452,7 +452,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
 
        /* Cluster local system nodes *must* have direct links */
        if (!is_slave(addr) && in_own_cluster(addr))
-               return 0;
+               return NULL;
 
        /* Look for cluster local router with direct link to node */
        router_addr = tipc_node_select_router(n_ptr, selector);
@@ -462,7 +462,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
        /* Slave nodes can only be accessed within own cluster via a 
           known router with direct link -- if no router was found,give up */
        if (is_slave(addr))
-               return 0;
+               return NULL;
 
        /* Inter zone/cluster -- find any direct link to remote cluster */
        addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
@@ -475,7 +475,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
        if (router_addr) 
                 return tipc_node_select(router_addr, selector);
 
-        return 0;
+        return NULL;
 }
 
 /**
index 29f7ae6..781126e 100644 (file)
@@ -121,7 +121,7 @@ static inline struct node *tipc_node_find(u32 addr)
                if (c_ptr)
                        return c_ptr->nodes[tipc_node(addr)];
        }
-       return 0;
+       return NULL;
 }
 
 static inline struct node *tipc_node_select(u32 addr, u32 selector)
index afeea12..cff4068 100644 (file)
@@ -47,7 +47,7 @@
 void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr, 
                       void *usr_handle, net_ev_handler handle_down)
 {
-       node_sub->node = 0;
+       node_sub->node = NULL;
        if (addr == tipc_own_addr)
                return;
        if (!tipc_addr_node_valid(addr)) {
index 72aae52..67e96cb 100644 (file)
@@ -54,8 +54,8 @@
 
 #define MAX_REJECT_SIZE 1024
 
-static struct sk_buff *msg_queue_head = 0;
-static struct sk_buff *msg_queue_tail = 0;
+static struct sk_buff *msg_queue_head = NULL;
+static struct sk_buff *msg_queue_tail = NULL;
 
 spinlock_t tipc_port_list_lock = SPIN_LOCK_UNLOCKED;
 static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;
@@ -67,27 +67,22 @@ static struct sk_buff* port_build_peer_abort_msg(struct port *,u32 err);
 static void port_timeout(unsigned long ref);
 
 
-static inline u32 port_peernode(struct port *p_ptr)
+static u32 port_peernode(struct port *p_ptr)
 {
        return msg_destnode(&p_ptr->publ.phdr);
 }
 
-static inline u32 port_peerport(struct port *p_ptr)
+static u32 port_peerport(struct port *p_ptr)
 {
        return msg_destport(&p_ptr->publ.phdr);
 }
 
-static inline u32 port_out_seqno(struct port *p_ptr)
+static u32 port_out_seqno(struct port *p_ptr)
 {
        return msg_transp_seqno(&p_ptr->publ.phdr);
 }
 
-static inline void port_set_out_seqno(struct port *p_ptr, u32 seqno) 
-{
-       msg_set_transp_seqno(&p_ptr->publ.phdr,seqno);
-}
-
-static inline void port_incr_out_seqno(struct port *p_ptr)
+static void port_incr_out_seqno(struct port *p_ptr)
 {
        struct tipc_msg *m = &p_ptr->publ.phdr;
 
@@ -258,11 +253,11 @@ u32 tipc_createport_raw(void *usr_handle,
        p_ptr->publ.usr_handle = usr_handle;
        INIT_LIST_HEAD(&p_ptr->wait_list);
        INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
-       p_ptr->congested_link = 0;
+       p_ptr->congested_link = NULL;
        p_ptr->max_pkt = MAX_PKT_DEFAULT;
        p_ptr->dispatcher = dispatcher;
        p_ptr->wakeup = wakeup;
-       p_ptr->user_port = 0;
+       p_ptr->user_port = NULL;
        k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
        spin_lock_bh(&tipc_port_list_lock);
        INIT_LIST_HEAD(&p_ptr->publications);
@@ -276,9 +271,9 @@ u32 tipc_createport_raw(void *usr_handle,
 int tipc_deleteport(u32 ref)
 {
        struct port *p_ptr;
-       struct sk_buff *buf = 0;
+       struct sk_buff *buf = NULL;
 
-       tipc_withdraw(ref, 0, 0);
+       tipc_withdraw(ref, 0, NULL);
        p_ptr = tipc_port_lock(ref);
        if (!p_ptr) 
                return -EINVAL;
@@ -329,13 +324,13 @@ void *tipc_get_handle(const u32 ref)
 
        p_ptr = tipc_port_lock(ref);
        if (!p_ptr)
-               return 0;
+               return NULL;
        handle = p_ptr->publ.usr_handle;
        tipc_port_unlock(p_ptr);
        return handle;
 }
 
-static inline int port_unreliable(struct port *p_ptr)
+static int port_unreliable(struct port *p_ptr)
 {
        return msg_src_droppable(&p_ptr->publ.phdr);
 }
@@ -364,7 +359,7 @@ int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
        return TIPC_OK;
 }
 
-static inline int port_unreturnable(struct port *p_ptr)
+static int port_unreturnable(struct port *p_ptr)
 {
        return msg_dest_droppable(&p_ptr->publ.phdr);
 }
@@ -475,7 +470,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)
 
        /* send self-abort message when rejecting on a connected port */
        if (msg_connected(msg)) {
-               struct sk_buff *abuf = 0;
+               struct sk_buff *abuf = NULL;
                struct port *p_ptr = tipc_port_lock(msg_destport(msg));
 
                if (p_ptr) {
@@ -510,7 +505,7 @@ int tipc_port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
 static void port_timeout(unsigned long ref)
 {
        struct port *p_ptr = tipc_port_lock(ref);
-       struct sk_buff *buf = 0;
+       struct sk_buff *buf = NULL;
 
        if (!p_ptr || !p_ptr->publ.connected)
                return;
@@ -540,7 +535,7 @@ static void port_timeout(unsigned long ref)
 static void port_handle_node_down(unsigned long ref)
 {
        struct port *p_ptr = tipc_port_lock(ref);
-       struct sk_buff* buf = 0;
+       struct sk_buff* buf = NULL;
 
        if (!p_ptr)
                return;
@@ -555,7 +550,7 @@ static struct sk_buff *port_build_self_abort_msg(struct port *p_ptr, u32 err)
        u32 imp = msg_importance(&p_ptr->publ.phdr);
 
        if (!p_ptr->publ.connected)
-               return 0;
+               return NULL;
        if (imp < TIPC_CRITICAL_IMPORTANCE)
                imp++;
        return port_build_proto_msg(p_ptr->publ.ref,
@@ -575,7 +570,7 @@ static struct sk_buff *port_build_peer_abort_msg(struct port *p_ptr, u32 err)
        u32 imp = msg_importance(&p_ptr->publ.phdr);
 
        if (!p_ptr->publ.connected)
-               return 0;
+               return NULL;
        if (imp < TIPC_CRITICAL_IMPORTANCE)
                imp++;
        return port_build_proto_msg(port_peerport(p_ptr),
@@ -594,8 +589,8 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf)
        struct tipc_msg *msg = buf_msg(buf);
        struct port *p_ptr = tipc_port_lock(msg_destport(msg));
        u32 err = TIPC_OK;
-       struct sk_buff *r_buf = 0;
-       struct sk_buff *abort_buf = 0;
+       struct sk_buff *r_buf = NULL;
+       struct sk_buff *abort_buf = NULL;
 
        msg_dbg(msg, "PORT<RECV<:");
 
@@ -804,7 +799,7 @@ static void port_dispatcher_sigh(void *dummy)
 
        spin_lock_bh(&queue_lock);
        buf = msg_queue_head;
-       msg_queue_head = 0;
+       msg_queue_head = NULL;
        spin_unlock_bh(&queue_lock);
 
        while (buf) {
@@ -991,8 +986,8 @@ static void port_wakeup_sh(unsigned long ref)
 {
        struct port *p_ptr;
        struct user_port *up_ptr;
-       tipc_continue_event cb = 0;
-       void *uh = 0;
+       tipc_continue_event cb = NULL;
+       void *uh = NULL;
 
        p_ptr = tipc_port_lock(ref);
        if (p_ptr) {
@@ -1016,7 +1011,7 @@ static void port_wakeup(struct tipc_port *p_ptr)
 void tipc_acknowledge(u32 ref, u32 ack)
 {
        struct port *p_ptr;
-       struct sk_buff *buf = 0;
+       struct sk_buff *buf = NULL;
 
        p_ptr = tipc_port_lock(ref);
        if (!p_ptr)
@@ -1062,7 +1057,7 @@ int tipc_createport(u32 user_ref,
        if (up_ptr == NULL) {
                return -ENOMEM;
        }
-       ref = tipc_createport_raw(0, port_dispatcher, port_wakeup, importance);
+       ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance);
        p_ptr = tipc_port_lock(ref);
        if (!p_ptr) {
                kfree(up_ptr);
@@ -1273,7 +1268,7 @@ int tipc_disconnect(u32 ref)
 int tipc_shutdown(u32 ref)
 {
        struct port *p_ptr;
-       struct sk_buff *buf = 0;
+       struct sk_buff *buf = NULL;
 
        p_ptr = tipc_port_lock(ref);
        if (!p_ptr)
index 5a13c2d..33bbf50 100644 (file)
@@ -61,7 +61,7 @@
  * because entry 0's reference field has the form XXXX|1--1.
  */
 
-struct ref_table tipc_ref_table = { 0 };
+struct ref_table tipc_ref_table = { NULL };
 
 static rwlock_t ref_table_lock = RW_LOCK_UNLOCKED;
 
@@ -86,7 +86,7 @@ int tipc_ref_table_init(u32 requested_size, u32 start)
        write_lock_bh(&ref_table_lock);
        index_mask = sz - 1;
        for (i = sz - 1; i >= 0; i--) {
-               table[i].object = 0;
+               table[i].object = NULL;
                table[i].lock = SPIN_LOCK_UNLOCKED;
                table[i].data.next_plus_upper = (start & ~index_mask) + i - 1;
        }
@@ -108,7 +108,7 @@ void tipc_ref_table_stop(void)
                return;
 
        vfree(tipc_ref_table.entries);
-       tipc_ref_table.entries = 0;
+       tipc_ref_table.entries = NULL;
 }
 
 /**
@@ -173,7 +173,7 @@ void tipc_ref_discard(u32 ref)
        assert(entry->data.reference == ref);
 
        /* mark entry as unused */
-       entry->object = 0;
+       entry->object = NULL;
        if (tipc_ref_table.first_free == 0)
                tipc_ref_table.first_free = index;
        else
index 4f8f9f4..6d20006 100644 (file)
@@ -92,7 +92,7 @@ static inline void *tipc_ref_lock(u32 ref)
                        return r->object;
                spin_unlock_bh(&r->lock);
        }
-       return 0;
+       return NULL;
 }
 
 /**
@@ -125,7 +125,7 @@ static inline void *tipc_ref_deref(u32 ref)
                if (likely(r->data.reference == ref))
                        return r->object;
        }
-       return 0;
+       return NULL;
 }
 
 #endif
index 67253bf..648a734 100644 (file)
@@ -88,7 +88,7 @@ static atomic_t tipc_queue_size = ATOMIC_INIT(0);
  * with non-socket interfaces.
  * See net.c for description of locking policy.
  */
-static inline void sock_lock(struct tipc_sock* tsock)
+static void sock_lock(struct tipc_sock* tsock)
 {
         spin_lock_bh(tsock->p->lock);       
 }
@@ -96,7 +96,7 @@ static inline void sock_lock(struct tipc_sock* tsock)
 /* 
  * sock_unlock(): Unlock a port/socket pair
  */
-static inline void sock_unlock(struct tipc_sock* tsock)
+static void sock_unlock(struct tipc_sock* tsock)
 {
         spin_unlock_bh(tsock->p->lock);
 }
@@ -119,7 +119,7 @@ static inline void sock_unlock(struct tipc_sock* tsock)
  * Returns pollmask value
  */
 
-static inline u32 pollmask(struct socket *sock)
+static u32 pollmask(struct socket *sock)
 {
        u32 mask;
 
@@ -144,7 +144,7 @@ static inline u32 pollmask(struct socket *sock)
  * @tsock: TIPC socket
  */
 
-static inline void advance_queue(struct tipc_sock *tsock)
+static void advance_queue(struct tipc_sock *tsock)
 {
         sock_lock(tsock);
        buf_discard(skb_dequeue(&tsock->sk.sk_receive_queue));
@@ -178,7 +178,7 @@ static int tipc_create(struct socket *sock, int protocol)
        if (unlikely(protocol != 0))
                return -EPROTONOSUPPORT;
 
-       ref = tipc_createport_raw(0, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE);
+       ref = tipc_createport_raw(NULL, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE);
        if (unlikely(!ref))
                return -ENOMEM;
 
@@ -265,7 +265,7 @@ static int release(struct socket *sock)
                sock_lock(tsock);
                buf = skb_dequeue(&sk->sk_receive_queue);
                if (!buf)
-                       tsock->p->usr_handle = 0;
+                       tsock->p->usr_handle = NULL;
                sock_unlock(tsock);
                if (!buf)
                        break;
@@ -319,7 +319,7 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
                return -ERESTARTSYS;
        
        if (unlikely(!uaddr_len)) {
-               res = tipc_withdraw(tsock->p->ref, 0, 0);
+               res = tipc_withdraw(tsock->p->ref, 0, NULL);
                goto exit;
        }
 
@@ -412,7 +412,7 @@ static unsigned int poll(struct file *file, struct socket *sock,
  * Returns 0 if permission is granted, otherwise errno
  */
 
-static inline int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
+static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
 {
        struct tipc_cfg_msg_hdr hdr;
 
@@ -695,7 +695,7 @@ static int auto_connect(struct socket *sock, struct tipc_sock *tsock,
  * Note: Address is not captured if not requested by receiver.
  */
 
-static inline void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
+static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
 {
         struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name;
 
@@ -721,7 +721,7 @@ static inline void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
  * Returns 0 if successful, otherwise errno
  */
 
-static inline int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, 
+static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
                                struct tipc_port *tport)
 {
        u32 anc_data[3];
@@ -1226,7 +1226,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
 {
    struct tipc_sock *tsock = tipc_sk(sock->sk);
    struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;
-   struct msghdr m = {0,};
+   struct msghdr m = {NULL,};
    struct sk_buff *buf;
    struct tipc_msg *msg;
    int res;
@@ -1251,7 +1251,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
    /* Send a 'SYN-' to destination */
 
    m.msg_name = dest;
-   if ((res = send_msg(0, sock, &m, 0)) < 0) {
+   if ((res = send_msg(NULL, sock, &m, 0)) < 0) {
           sock->state = SS_DISCONNECTING;
           return res;
    }
@@ -1367,9 +1367,9 @@ static int accept(struct socket *sock, struct socket *newsock, int flags)
 
                msg_dbg(msg,"<ACC<: ");
                 if (!msg_data_sz(msg)) {
-                        struct msghdr m = {0,};
+                        struct msghdr m = {NULL,};
 
-                        send_packet(0, newsock, &m, 0);      
+                        send_packet(NULL, newsock, &m, 0);
                         advance_queue(tsock);
                 } else {
                        sock_lock(tsock);
index 5ff38b9..c5f026c 100644 (file)
@@ -86,7 +86,7 @@ static struct top_srv topsrv = { 0 };
  * Returns converted value
  */
 
-static inline u32 htohl(u32 in, int swap)
+static u32 htohl(u32 in, int swap)
 {
        char *c = (char *)&in;
 
@@ -381,7 +381,7 @@ static void subscr_named_msg_event(void *usr_handle,
                                   struct tipc_name_seq const *dest)
 {
        struct subscriber *subscriber;
-       struct iovec msg_sect = {0, 0};
+       struct iovec msg_sect = {NULL, 0};
        spinlock_t *subscriber_lock;
 
        dbg("subscr_named_msg_event: orig = %x own = %x,\n",
@@ -413,13 +413,13 @@ static void subscr_named_msg_event(void *usr_handle,
        tipc_createport(topsrv.user_ref,
                        (void *)(unsigned long)subscriber->ref,
                        importance,
-                       0,
-                       0,
+                       NULL,
+                       NULL,
                        subscr_conn_shutdown_event,
-                       0,
-                       0,
+                       NULL,
+                       NULL,
                        subscr_conn_msg_event,
-                       0,
+                       NULL,
                        &subscriber->port_ref);
        if (subscriber->port_ref == 0) {
                warn("Memory squeeze; failed to create subscription port\n");
@@ -461,22 +461,22 @@ int tipc_subscr_start(void)
        INIT_LIST_HEAD(&topsrv.subscriber_list);
 
        spin_lock_bh(&topsrv.lock);
-       res = tipc_attach(&topsrv.user_ref, 0, 0);
+       res = tipc_attach(&topsrv.user_ref, NULL, NULL);
        if (res) {
                spin_unlock_bh(&topsrv.lock);
                return res;
        }
 
        res = tipc_createport(topsrv.user_ref,
-                             0,
+                             NULL,
                              TIPC_CRITICAL_IMPORTANCE,
-                             0,
-                             0,
-                             0,
-                             0,
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL,
                              subscr_named_msg_event,
-                             0,
-                             0,
+                             NULL,
+                             NULL,
                              &topsrv.setup_port);
        if (res)
                goto failed;
index 106200d..3f3f933 100644 (file)
@@ -65,7 +65,7 @@ struct tipc_user {
 #define MAX_USERID 64
 #define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user))
 
-static struct tipc_user *users = 0;
+static struct tipc_user *users = NULL;
 static u32 next_free_user = MAX_USERID + 1;
 static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED;
 
@@ -149,7 +149,7 @@ void tipc_reg_stop(void)
                        reg_callback(&users[id]);
        }
        kfree(users);
-       users = 0;
+       users = NULL;
 }
 
 /**
index 7c11f7f..2803e1b 100644 (file)
 
 struct _zone *tipc_zone_create(u32 addr)
 {
-       struct _zone *z_ptr = 0;
+       struct _zone *z_ptr = NULL;
        u32 z_num;
 
        if (!tipc_addr_domain_valid(addr))
-               return 0;
+               return NULL;
 
        z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC);
        if (z_ptr != NULL) {
@@ -114,10 +114,10 @@ struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref
        u32 c_num;
 
        if (!z_ptr)
-               return 0;
+               return NULL;
        c_ptr = z_ptr->clusters[tipc_cluster(addr)];
        if (!c_ptr)
-               return 0;
+               return NULL;
        n_ptr = tipc_cltr_select_node(c_ptr, ref);
        if (n_ptr)
                return n_ptr;
@@ -126,12 +126,12 @@ struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref
        for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
                c_ptr = z_ptr->clusters[c_num];
                if (!c_ptr)
-                       return 0;
+                       return NULL;
                n_ptr = tipc_cltr_select_node(c_ptr, ref);
                if (n_ptr)
                        return n_ptr;
        }
-       return 0;
+       return NULL;
 }
 
 u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref)
index c323cc6..2b4cc2e 100644 (file)
@@ -566,7 +566,7 @@ static struct sock * unix_create1(struct socket *sock)
        u->mnt    = NULL;
        spin_lock_init(&u->lock);
        atomic_set(&u->inflight, sock ? 0 : -1);
-       init_MUTEX(&u->readsem); /* single task reading lock */
+       mutex_init(&u->readlock); /* single task reading lock */
        init_waitqueue_head(&u->peer_wait);
        unix_insert_socket(unix_sockets_unbound, sk);
 out:
@@ -623,7 +623,7 @@ static int unix_autobind(struct socket *sock)
        struct unix_address * addr;
        int err;
 
-       down(&u->readsem);
+       mutex_lock(&u->readlock);
 
        err = 0;
        if (u->addr)
@@ -661,7 +661,7 @@ retry:
        spin_unlock(&unix_table_lock);
        err = 0;
 
-out:   up(&u->readsem);
+out:   mutex_unlock(&u->readlock);
        return err;
 }
 
@@ -744,7 +744,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                goto out;
        addr_len = err;
 
-       down(&u->readsem);
+       mutex_lock(&u->readlock);
 
        err = -EINVAL;
        if (u->addr)
@@ -816,7 +816,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 out_unlock:
        spin_unlock(&unix_table_lock);
 out_up:
-       up(&u->readsem);
+       mutex_unlock(&u->readlock);
 out:
        return err;
 
@@ -1427,15 +1427,15 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
        while(sent < len)
        {
                /*
-                *      Optimisation for the fact that under 0.01% of X messages typically
-                *      need breaking up.
+                *      Optimisation for the fact that under 0.01% of X
+                *      messages typically need breaking up.
                 */
 
-               size=len-sent;
+               size = len-sent;
 
                /* Keep two messages in the pipe so it schedules better */
-               if (size > sk->sk_sndbuf / 2 - 64)
-                       size = sk->sk_sndbuf / 2 - 64;
+               if (size > ((sk->sk_sndbuf >> 1) - 64))
+                       size = (sk->sk_sndbuf >> 1) - 64;
 
                if (size > SKB_MAX_ALLOC)
                        size = SKB_MAX_ALLOC;
@@ -1545,7 +1545,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        msg->msg_namelen = 0;
 
-       down(&u->readsem);
+       mutex_lock(&u->readlock);
 
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb)
@@ -1600,7 +1600,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
 out_free:
        skb_free_datagram(sk,skb);
 out_unlock:
-       up(&u->readsem);
+       mutex_unlock(&u->readlock);
 out:
        return err;
 }
@@ -1676,7 +1676,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                memset(&tmp_scm, 0, sizeof(tmp_scm));
        }
 
-       down(&u->readsem);
+       mutex_lock(&u->readlock);
 
        do
        {
@@ -1700,7 +1700,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                        err = -EAGAIN;
                        if (!timeo)
                                break;
-                       up(&u->readsem);
+                       mutex_unlock(&u->readlock);
 
                        timeo = unix_stream_data_wait(sk, timeo);
 
@@ -1708,7 +1708,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                                err = sock_intr_errno(timeo);
                                goto out;
                        }
-                       down(&u->readsem);
+                       mutex_lock(&u->readlock);
                        continue;
                }
 
@@ -1774,7 +1774,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                }
        } while (size);
 
-       up(&u->readsem);
+       mutex_unlock(&u->readlock);
        scm_recv(sock, msg, siocb->scm, flags);
 out:
        return copied ? : err;
index 411802b..746c2f4 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/netdevice.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 
 #include <net/sock.h>
 #include <net/af_unix.h>
@@ -169,7 +170,7 @@ static void maybe_unmark_and_push(struct sock *x)
 
 void unix_gc(void)
 {
-       static DECLARE_MUTEX(unix_gc_sem);
+       static DEFINE_MUTEX(unix_gc_sem);
        int i;
        struct sock *s;
        struct sk_buff_head hitlist;
@@ -179,7 +180,7 @@ void unix_gc(void)
         *      Avoid a recursive GC.
         */
 
-       if (down_trylock(&unix_gc_sem))
+       if (!mutex_trylock(&unix_gc_sem))
                return;
 
        spin_lock(&unix_table_lock);
@@ -308,5 +309,5 @@ void unix_gc(void)
         */
 
        __skb_queue_purge(&hitlist);
-       up(&unix_gc_sem);
+       mutex_unlock(&unix_gc_sem);
 }
index ae62054..f5eae9f 100644 (file)
@@ -26,8 +26,8 @@
 #include <net/xfrm.h>
 #include <net/ip.h>
 
-DECLARE_MUTEX(xfrm_cfg_sem);
-EXPORT_SYMBOL(xfrm_cfg_sem);
+DEFINE_MUTEX(xfrm_cfg_mutex);
+EXPORT_SYMBOL(xfrm_cfg_mutex);
 
 static DEFINE_RWLOCK(xfrm_policy_lock);
 
@@ -203,7 +203,7 @@ static void xfrm_policy_timer(unsigned long data)
        }
 
        if (warn)
-               km_policy_expired(xp, dir, 0);
+               km_policy_expired(xp, dir, 0, 0);
        if (next != LONG_MAX &&
            !mod_timer(&xp->timer, jiffies + make_jiffies(next)))
                xfrm_pol_hold(xp);
@@ -216,7 +216,7 @@ out:
 expired:
        read_unlock(&xp->lock);
        if (!xfrm_policy_delete(xp, dir))
-               km_policy_expired(xp, dir, 1);
+               km_policy_expired(xp, dir, 1, 0);
        xfrm_pol_put(xp);
 }
 
@@ -621,6 +621,7 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
        }
        return -ENOENT;
 }
+EXPORT_SYMBOL(xfrm_policy_delete);
 
 int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
 {
index c656cba..a8e14dc 100644 (file)
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
+struct sock *xfrm_nl;
+EXPORT_SYMBOL(xfrm_nl);
+
+u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME;
+EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
+
+u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE;
+EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
+
 /* Each xfrm_state may be linked to two tables:
 
    1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
@@ -50,18 +59,20 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock);
 
 static int xfrm_state_gc_flush_bundles;
 
-static int __xfrm_state_delete(struct xfrm_state *x);
+int __xfrm_state_delete(struct xfrm_state *x);
 
 static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
 static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
-static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
-static void km_state_expired(struct xfrm_state *x, int hard);
+int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
+void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
 
 static void xfrm_state_gc_destroy(struct xfrm_state *x)
 {
        if (del_timer(&x->timer))
                BUG();
+       if (del_timer(&x->rtimer))
+               BUG();
        kfree(x->aalg);
        kfree(x->ealg);
        kfree(x->calg);
@@ -153,7 +164,7 @@ static void xfrm_timer_handler(unsigned long data)
 
        x->km.dying = warn;
        if (warn)
-               km_state_expired(x, 0);
+               km_state_expired(x, 0, 0);
 resched:
        if (next != LONG_MAX &&
            !mod_timer(&x->timer, jiffies + make_jiffies(next)))
@@ -168,13 +179,15 @@ expired:
                goto resched;
        }
        if (!__xfrm_state_delete(x) && x->id.spi)
-               km_state_expired(x, 1);
+               km_state_expired(x, 1, 0);
 
 out:
        spin_unlock(&x->lock);
        xfrm_state_put(x);
 }
 
+static void xfrm_replay_timer_handler(unsigned long data);
+
 struct xfrm_state *xfrm_state_alloc(void)
 {
        struct xfrm_state *x;
@@ -190,11 +203,16 @@ struct xfrm_state *xfrm_state_alloc(void)
                init_timer(&x->timer);
                x->timer.function = xfrm_timer_handler;
                x->timer.data     = (unsigned long)x;
+               init_timer(&x->rtimer);
+               x->rtimer.function = xfrm_replay_timer_handler;
+               x->rtimer.data     = (unsigned long)x;
                x->curlft.add_time = (unsigned long)xtime.tv_sec;
                x->lft.soft_byte_limit = XFRM_INF;
                x->lft.soft_packet_limit = XFRM_INF;
                x->lft.hard_byte_limit = XFRM_INF;
                x->lft.hard_packet_limit = XFRM_INF;
+               x->replay_maxage = 0;
+               x->replay_maxdiff = 0;
                spin_lock_init(&x->lock);
        }
        return x;
@@ -212,7 +230,7 @@ void __xfrm_state_destroy(struct xfrm_state *x)
 }
 EXPORT_SYMBOL(__xfrm_state_destroy);
 
-static int __xfrm_state_delete(struct xfrm_state *x)
+int __xfrm_state_delete(struct xfrm_state *x)
 {
        int err = -ESRCH;
 
@@ -228,6 +246,8 @@ static int __xfrm_state_delete(struct xfrm_state *x)
                spin_unlock(&xfrm_state_lock);
                if (del_timer(&x->timer))
                        __xfrm_state_put(x);
+               if (del_timer(&x->rtimer))
+                       __xfrm_state_put(x);
 
                /* The number two in this test is the reference
                 * mentioned in the comment below plus the reference
@@ -249,6 +269,7 @@ static int __xfrm_state_delete(struct xfrm_state *x)
 
        return err;
 }
+EXPORT_SYMBOL(__xfrm_state_delete);
 
 int xfrm_state_delete(struct xfrm_state *x)
 {
@@ -426,6 +447,10 @@ static void __xfrm_state_insert(struct xfrm_state *x)
        if (!mod_timer(&x->timer, jiffies + HZ))
                xfrm_state_hold(x);
 
+       if (x->replay_maxage &&
+           !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
+               xfrm_state_hold(x);
+
        wake_up(&km_waitq);
 }
 
@@ -580,7 +605,7 @@ int xfrm_state_check_expire(struct xfrm_state *x)
            (x->curlft.bytes >= x->lft.soft_byte_limit ||
             x->curlft.packets >= x->lft.soft_packet_limit)) {
                x->km.dying = 1;
-               km_state_expired(x, 0);
+               km_state_expired(x, 0, 0);
        }
        return 0;
 }
@@ -762,6 +787,61 @@ out:
 }
 EXPORT_SYMBOL(xfrm_state_walk);
 
+
+void xfrm_replay_notify(struct xfrm_state *x, int event)
+{
+       struct km_event c;
+       /* we send notify messages in case
+        *  1. we updated on of the sequence numbers, and the seqno difference
+        *     is at least x->replay_maxdiff, in this case we also update the
+        *     timeout of our timer function
+        *  2. if x->replay_maxage has elapsed since last update,
+        *     and there were changes
+        *
+        *  The state structure must be locked!
+        */
+
+       switch (event) {
+       case XFRM_REPLAY_UPDATE:
+               if (x->replay_maxdiff &&
+                   (x->replay.seq - x->preplay.seq < x->replay_maxdiff) &&
+                   (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))
+                       return;
+
+               break;
+
+       case XFRM_REPLAY_TIMEOUT:
+               if ((x->replay.seq == x->preplay.seq) &&
+                   (x->replay.bitmap == x->preplay.bitmap) &&
+                   (x->replay.oseq == x->preplay.oseq))
+                       return;
+
+               break;
+       }
+
+       memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state));
+       c.event = XFRM_MSG_NEWAE;
+       c.data.aevent = event;
+       km_state_notify(x, &c);
+
+       if (x->replay_maxage &&
+           !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
+               xfrm_state_hold(x);
+}
+EXPORT_SYMBOL(xfrm_replay_notify);
+
+static void xfrm_replay_timer_handler(unsigned long data)
+{
+       struct xfrm_state *x = (struct xfrm_state*)data;
+
+       spin_lock(&x->lock);
+
+       if (xfrm_aevent_is_on() && x->km.state == XFRM_STATE_VALID)
+               xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT);
+
+       spin_unlock(&x->lock);
+}
+
 int xfrm_replay_check(struct xfrm_state *x, u32 seq)
 {
        u32 diff;
@@ -805,6 +885,9 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq)
                diff = x->replay.seq - seq;
                x->replay.bitmap |= (1U << diff);
        }
+
+       if (xfrm_aevent_is_on())
+               xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 }
 EXPORT_SYMBOL(xfrm_replay_advance);
 
@@ -835,11 +918,12 @@ void km_state_notify(struct xfrm_state *x, struct km_event *c)
 EXPORT_SYMBOL(km_policy_notify);
 EXPORT_SYMBOL(km_state_notify);
 
-static void km_state_expired(struct xfrm_state *x, int hard)
+void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
 {
        struct km_event c;
 
        c.data.hard = hard;
+       c.pid = pid;
        c.event = XFRM_MSG_EXPIRE;
        km_state_notify(x, &c);
 
@@ -847,11 +931,12 @@ static void km_state_expired(struct xfrm_state *x, int hard)
                wake_up(&km_waitq);
 }
 
+EXPORT_SYMBOL(km_state_expired);
 /*
  * We send to all registered managers regardless of failure
  * We are happy with one success
 */
-static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
+int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
 {
        int err = -EINVAL, acqret;
        struct xfrm_mgr *km;
@@ -865,6 +950,7 @@ static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_polic
        read_unlock(&xfrm_km_lock);
        return err;
 }
+EXPORT_SYMBOL(km_query);
 
 int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)
 {
@@ -883,17 +969,19 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)
 }
 EXPORT_SYMBOL(km_new_mapping);
 
-void km_policy_expired(struct xfrm_policy *pol, int dir, int hard)
+void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
 {
        struct km_event c;
 
        c.data.hard = hard;
+       c.pid = pid;
        c.event = XFRM_MSG_POLEXPIRE;
        km_policy_notify(pol, dir, &c);
 
        if (hard)
                wake_up(&km_waitq);
 }
+EXPORT_SYMBOL(km_policy_expired);
 
 int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
 {
index 7de1755..81d1005 100644 (file)
@@ -28,8 +28,6 @@
 #include <net/netlink.h>
 #include <asm/uaccess.h>
 
-static struct sock *xfrm_nl;
-
 static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)
 {
        struct rtattr *rt = xfrma[type - 1];
@@ -103,9 +101,6 @@ static inline int verify_sec_ctx_len(struct rtattr **xfrma)
 
        uctx = RTA_DATA(rt);
 
-       if (uctx->ctx_len > PAGE_SIZE)
-               return -EINVAL;
-
        len += sizeof(struct xfrm_user_sec_ctx);
        len += uctx->ctx_len;
 
@@ -276,6 +271,56 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *
        x->props.flags = p->flags;
 }
 
+/*
+ * someday when pfkey also has support, we could have the code
+ * somehow made shareable and move it to xfrm_state.c - JHS
+ *
+*/
+static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma)
+{
+       int err = - EINVAL;
+       struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1];
+       struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1];
+       struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1];
+       struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1];
+
+       if (rp) {
+               struct xfrm_replay_state *replay;
+               if (RTA_PAYLOAD(rp) < sizeof(*replay))
+                       goto error;
+               replay = RTA_DATA(rp);
+               memcpy(&x->replay, replay, sizeof(*replay));
+               memcpy(&x->preplay, replay, sizeof(*replay));
+       }
+
+       if (lt) {
+               struct xfrm_lifetime_cur *ltime;
+               if (RTA_PAYLOAD(lt) < sizeof(*ltime))
+                       goto error;
+               ltime = RTA_DATA(lt);
+               x->curlft.bytes = ltime->bytes;
+               x->curlft.packets = ltime->packets;
+               x->curlft.add_time = ltime->add_time;
+               x->curlft.use_time = ltime->use_time;
+       }
+
+       if (et) {
+               if (RTA_PAYLOAD(et) < sizeof(u32))
+                       goto error;
+               x->replay_maxage = *(u32*)RTA_DATA(et);
+       }
+
+       if (rt) {
+               if (RTA_PAYLOAD(rt) < sizeof(u32))
+                       goto error;
+               x->replay_maxdiff = *(u32*)RTA_DATA(rt);
+       }
+
+       return 0;
+error:
+       return err;
+}
+
 static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
                                               struct rtattr **xfrma,
                                               int *errp)
@@ -311,6 +356,18 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
                goto error;
 
        x->km.seq = p->seq;
+       x->replay_maxdiff = sysctl_xfrm_aevent_rseqth;
+       /* sysctl_xfrm_aevent_etime is in 100ms units */
+       x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M;
+       x->preplay.bitmap = 0;
+       x->preplay.seq = x->replay.seq+x->replay_maxdiff;
+       x->preplay.oseq = x->replay.oseq +x->replay_maxdiff;
+
+       /* override default values from above */
+
+       err = xfrm_update_ae_params(x, (struct rtattr **)xfrma);
+       if (err < 0)
+               goto error;
 
        return x;
 
@@ -1025,9 +1082,142 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma
        return 0;
 }
 
-static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+
+static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
+{
+       struct xfrm_aevent_id *id;
+       struct nlmsghdr *nlh;
+       struct xfrm_lifetime_cur ltime;
+       unsigned char *b = skb->tail;
+
+       nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id));
+       id = NLMSG_DATA(nlh);
+       nlh->nlmsg_flags = 0;
+
+       id->sa_id.daddr = x->id.daddr;
+       id->sa_id.spi = x->id.spi;
+       id->sa_id.family = x->props.family;
+       id->sa_id.proto = x->id.proto;
+       id->flags = c->data.aevent;
+
+       RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay);
+
+       ltime.bytes = x->curlft.bytes;
+       ltime.packets = x->curlft.packets;
+       ltime.add_time = x->curlft.add_time;
+       ltime.use_time = x->curlft.use_time;
+
+       RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), &ltime);
+
+       if (id->flags&XFRM_AE_RTHR) {
+               RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff);
+       }
+
+       if (id->flags&XFRM_AE_ETHR) {
+               u32 etimer = x->replay_maxage*10/HZ;
+               RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer);
+       }
+
+       nlh->nlmsg_len = skb->tail - b;
+       return skb->len;
+
+rtattr_failure:
+nlmsg_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+       struct xfrm_state *x;
+       struct sk_buff *r_skb;
+       int err;
+       struct km_event c;
+       struct xfrm_aevent_id *p = NLMSG_DATA(nlh);
+       int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
+       struct xfrm_usersa_id *id = &p->sa_id;
+
+       len += RTA_SPACE(sizeof(struct xfrm_replay_state));
+       len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur));
+
+       if (p->flags&XFRM_AE_RTHR)
+               len+=RTA_SPACE(sizeof(u32));
+
+       if (p->flags&XFRM_AE_ETHR)
+               len+=RTA_SPACE(sizeof(u32));
+
+       r_skb = alloc_skb(len, GFP_ATOMIC);
+       if (r_skb == NULL)
+               return -ENOMEM;
+
+       x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family);
+       if (x == NULL) {
+               kfree(r_skb);
+               return -ESRCH;
+       }
+
+       /*
+        * XXX: is this lock really needed - none of the other
+        * gets lock (the concern is things getting updated
+        * while we are still reading) - jhs
+       */
+       spin_lock_bh(&x->lock);
+       c.data.aevent = p->flags;
+       c.seq = nlh->nlmsg_seq;
+       c.pid = nlh->nlmsg_pid;
+
+       if (build_aevent(r_skb, x, &c) < 0)
+               BUG();
+       err = netlink_unicast(xfrm_nl, r_skb,
+                             NETLINK_CB(skb).pid, MSG_DONTWAIT);
+       spin_unlock_bh(&x->lock);
+       xfrm_state_put(x);
+       return err;
+}
+
+static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
 {
+       struct xfrm_state *x;
        struct km_event c;
+       int err = - EINVAL;
+       struct xfrm_aevent_id *p = NLMSG_DATA(nlh);
+       struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1];
+       struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1];
+
+       if (!lt && !rp)
+               return err;
+
+       /* pedantic mode - thou shalt sayeth replaceth */
+       if (!(nlh->nlmsg_flags&NLM_F_REPLACE))
+               return err;
+
+       x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
+       if (x == NULL)
+               return -ESRCH;
+
+       if (x->km.state != XFRM_STATE_VALID)
+               goto out;
+
+       spin_lock_bh(&x->lock);
+       err = xfrm_update_ae_params(x,(struct rtattr **)xfrma);
+       spin_unlock_bh(&x->lock);
+       if (err < 0)
+               goto out;
+
+       c.event = nlh->nlmsg_type;
+       c.seq = nlh->nlmsg_seq;
+       c.pid = nlh->nlmsg_pid;
+       c.data.aevent = XFRM_AE_CU;
+       km_state_notify(x, &c);
+       err = 0;
+out:
+       xfrm_state_put(x);
+       return err;
+}
+
+static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+struct km_event c;
 
        xfrm_policy_flush();
        c.event = nlh->nlmsg_type;
@@ -1037,6 +1227,139 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **x
        return 0;
 }
 
+static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+       struct xfrm_policy *xp;
+       struct xfrm_user_polexpire *up = NLMSG_DATA(nlh);
+       struct xfrm_userpolicy_info *p = &up->pol;
+       int err = -ENOENT;
+
+       if (p->index)
+               xp = xfrm_policy_byid(p->dir, p->index, 0);
+       else {
+               struct rtattr **rtattrs = (struct rtattr **)xfrma;
+               struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1];
+               struct xfrm_policy tmp;
+
+               err = verify_sec_ctx_len(rtattrs);
+               if (err)
+                       return err;
+
+               memset(&tmp, 0, sizeof(struct xfrm_policy));
+               if (rt) {
+                       struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
+
+                       if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
+                               return err;
+               }
+               xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0);
+               security_xfrm_policy_free(&tmp);
+       }
+
+       if (xp == NULL)
+               return err;
+                                                                                       read_lock(&xp->lock);
+       if (xp->dead) {
+               read_unlock(&xp->lock);
+               goto out;
+       }
+
+       read_unlock(&xp->lock);
+       err = 0;
+       if (up->hard) {
+               xfrm_policy_delete(xp, p->dir);
+       } else {
+               // reset the timers here?
+               printk("Dont know what to do with soft policy expire\n");
+       }
+       km_policy_expired(xp, p->dir, up->hard, current->pid);
+
+out:
+       xfrm_pol_put(xp);
+       return err;
+}
+
+static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+       struct xfrm_state *x;
+       int err;
+       struct xfrm_user_expire *ue = NLMSG_DATA(nlh);
+       struct xfrm_usersa_info *p = &ue->state;
+
+       x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family);
+               err = -ENOENT;
+
+       if (x == NULL)
+               return err;
+
+       err = -EINVAL;
+
+       spin_lock_bh(&x->lock);
+       if (x->km.state != XFRM_STATE_VALID)
+               goto out;
+       km_state_expired(x, ue->hard, current->pid);
+
+       if (ue->hard)
+               __xfrm_state_delete(x);
+out:
+       spin_unlock_bh(&x->lock);
+       xfrm_state_put(x);
+       return err;
+}
+
+static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
+{
+       struct xfrm_policy *xp;
+       struct xfrm_user_tmpl *ut;
+       int i;
+       struct rtattr *rt = xfrma[XFRMA_TMPL-1];
+
+       struct xfrm_user_acquire *ua = NLMSG_DATA(nlh);
+       struct xfrm_state *x = xfrm_state_alloc();
+       int err = -ENOMEM;
+
+       if (!x)
+               return err;
+
+       err = verify_newpolicy_info(&ua->policy);
+       if (err) {
+               printk("BAD policy passed\n");
+               kfree(x);
+               return err;
+       }
+
+       /*   build an XP */
+       xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err);        if (!xp) {
+               kfree(x);
+               return err;
+       }
+
+       memcpy(&x->id, &ua->id, sizeof(ua->id));
+       memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr));
+       memcpy(&x->sel, &ua->sel, sizeof(ua->sel));
+
+       ut = RTA_DATA(rt);
+       /* extract the templates and for each call km_key */
+       for (i = 0; i < xp->xfrm_nr; i++, ut++) {
+               struct xfrm_tmpl *t = &xp->xfrm_vec[i];
+               memcpy(&x->id, &t->id, sizeof(x->id));
+               x->props.mode = t->mode;
+               x->props.reqid = t->reqid;
+               x->props.family = ut->family;
+               t->aalgos = ua->aalgos;
+               t->ealgos = ua->ealgos;
+               t->calgos = ua->calgos;
+               err = km_query(x, t, xp);
+
+       }
+
+       kfree(x);
+       kfree(xp);
+
+       return 0;
+}
+
+
 #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type))
 
 static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
@@ -1054,6 +1377,8 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
        [XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
        [XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
        [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0),
+       [XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
+       [XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
 };
 
 #undef XMSGSIZE
@@ -1071,10 +1396,15 @@ static struct xfrm_link {
        [XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
                                                   .dump = xfrm_dump_policy   },
        [XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
+       [XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },
+       [XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
        [XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
        [XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
+       [XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},
        [XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },
        [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
+       [XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },
+       [XFRM_MSG_GETAE       - XFRM_MSG_BASE] = { .doit = xfrm_get_ae  },
 };
 
 static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
@@ -1156,26 +1486,26 @@ static void xfrm_netlink_rcv(struct sock *sk, int len)
        unsigned int qlen = 0;
 
        do {
-               down(&xfrm_cfg_sem);
+               mutex_lock(&xfrm_cfg_mutex);
                netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg);
-               up(&xfrm_cfg_sem);
+               mutex_unlock(&xfrm_cfg_mutex);
 
        } while (qlen);
 }
 
-static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard)
+static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
 {
        struct xfrm_user_expire *ue;
        struct nlmsghdr *nlh;
        unsigned char *b = skb->tail;
 
-       nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE,
+       nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE,
                        sizeof(*ue));
        ue = NLMSG_DATA(nlh);
        nlh->nlmsg_flags = 0;
 
        copy_to_user_state(x, &ue->state);
-       ue->hard = (hard != 0) ? 1 : 0;
+       ue->hard = (c->data.hard != 0) ? 1 : 0;
 
        nlh->nlmsg_len = skb->tail - b;
        return skb->len;
@@ -1194,13 +1524,31 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
        if (skb == NULL)
                return -ENOMEM;
 
-       if (build_expire(skb, x, c->data.hard) < 0)
+       if (build_expire(skb, x, c) < 0)
                BUG();
 
        NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE;
        return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
 }
 
+static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c)
+{
+       struct sk_buff *skb;
+       int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
+
+       len += RTA_SPACE(sizeof(struct xfrm_replay_state));
+       len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur));
+       skb = alloc_skb(len, GFP_ATOMIC);
+       if (skb == NULL)
+               return -ENOMEM;
+
+       if (build_aevent(skb, x, c) < 0)
+               BUG();
+
+       NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS;
+       return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC);
+}
+
 static int xfrm_notify_sa_flush(struct km_event *c)
 {
        struct xfrm_usersa_flush *p;
@@ -1313,6 +1661,8 @@ static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
        switch (c->event) {
        case XFRM_MSG_EXPIRE:
                return xfrm_exp_state_notify(x, c);
+       case XFRM_MSG_NEWAE:
+               return xfrm_aevent_state_notify(x, c);
        case XFRM_MSG_DELSA:
        case XFRM_MSG_UPDSA:
        case XFRM_MSG_NEWSA:
@@ -1443,13 +1793,14 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt,
 }
 
 static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
-                          int dir, int hard)
+                          int dir, struct km_event *c)
 {
        struct xfrm_user_polexpire *upe;
        struct nlmsghdr *nlh;
+       int hard = c->data.hard;
        unsigned char *b = skb->tail;
 
-       nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe));
+       nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe));
        upe = NLMSG_DATA(nlh);
        nlh->nlmsg_flags = 0;
 
@@ -1480,7 +1831,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve
        if (skb == NULL)
                return -ENOMEM;
 
-       if (build_polexpire(skb, xp, dir, c->data.hard) < 0)
+       if (build_polexpire(skb, xp, dir, c) < 0)
                BUG();
 
        NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE;
@@ -1596,12 +1947,15 @@ static struct xfrm_mgr netlink_mgr = {
 
 static int __init xfrm_user_init(void)
 {
+       struct sock *nlsk;
+
        printk(KERN_INFO "Initializing IPsec netlink socket\n");
 
-       xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
-                                       xfrm_netlink_rcv, THIS_MODULE);
-       if (xfrm_nl == NULL)
+       nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
+                                    xfrm_netlink_rcv, THIS_MODULE);
+       if (nlsk == NULL)
                return -ENOMEM;
+       rcu_assign_pointer(xfrm_nl, nlsk);
 
        xfrm_register_km(&netlink_mgr);
 
@@ -1610,11 +1964,16 @@ static int __init xfrm_user_init(void)
 
 static void __exit xfrm_user_exit(void)
 {
+       struct sock *nlsk = xfrm_nl;
+
        xfrm_unregister_km(&netlink_mgr);
-       sock_release(xfrm_nl->sk_socket);
+       rcu_assign_pointer(xfrm_nl, NULL);
+       synchronize_rcu();
+       sock_release(nlsk->sk_socket);
 }
 
 module_init(xfrm_user_init);
 module_exit(xfrm_user_exit);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
+
index ee46478..d8153f5 100644 (file)
@@ -52,9 +52,9 @@ is_reserved_hash (register const char *str, register unsigned int len)
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
-      71, 71, 71, 71, 71, 71, 71, 71, 71, 15,
-      71, 71, 71, 71, 71, 71, 15, 71, 71, 71,
-      10, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+      71, 71, 71, 71, 71, 71, 71, 71, 71,  0,
+      71, 71, 71, 71, 71, 71, 35, 71, 71, 71,
+       5, 71, 71, 71, 71, 71, 71, 71, 71, 71,
       71, 71, 71, 71, 71,  0, 71,  0, 71,  5,
        5,  0, 10, 20, 71, 25, 71, 71, 20,  0,
       20, 30, 25, 71, 10,  5,  0, 20, 15, 71,
@@ -84,9 +84,9 @@ is_reserved_word (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 41,
+      TOTAL_KEYWORDS = 42,
       MIN_WORD_LENGTH = 3,
-      MAX_WORD_LENGTH = 17,
+      MAX_WORD_LENGTH = 24,
       MIN_HASH_VALUE = 3,
       MAX_HASH_VALUE = 70
     };
@@ -94,104 +94,105 @@ is_reserved_word (register const char *str, register unsigned int len)
   static const struct resword wordlist[] =
     {
       {""}, {""}, {""},
-#line 24 "scripts/genksyms/keywords.gperf"
+#line 25 "scripts/genksyms/keywords.gperf"
       {"asm", ASM_KEYW},
       {""},
-#line 7 "scripts/genksyms/keywords.gperf"
+#line 8 "scripts/genksyms/keywords.gperf"
       {"__asm", ASM_KEYW},
       {""},
-#line 8 "scripts/genksyms/keywords.gperf"
+#line 9 "scripts/genksyms/keywords.gperf"
       {"__asm__", ASM_KEYW},
       {""},
-#line 21 "scripts/genksyms/keywords.gperf"
+#line 22 "scripts/genksyms/keywords.gperf"
       {"_restrict", RESTRICT_KEYW},
-#line 50 "scripts/genksyms/keywords.gperf"
+#line 51 "scripts/genksyms/keywords.gperf"
       {"__typeof__", TYPEOF_KEYW},
-#line 9 "scripts/genksyms/keywords.gperf"
+#line 10 "scripts/genksyms/keywords.gperf"
       {"__attribute", ATTRIBUTE_KEYW},
-#line 11 "scripts/genksyms/keywords.gperf"
+#line 12 "scripts/genksyms/keywords.gperf"
       {"__const", CONST_KEYW},
-#line 10 "scripts/genksyms/keywords.gperf"
+#line 11 "scripts/genksyms/keywords.gperf"
       {"__attribute__", ATTRIBUTE_KEYW},
-#line 12 "scripts/genksyms/keywords.gperf"
+#line 13 "scripts/genksyms/keywords.gperf"
       {"__const__", CONST_KEYW},
-#line 16 "scripts/genksyms/keywords.gperf"
+#line 17 "scripts/genksyms/keywords.gperf"
       {"__signed__", SIGNED_KEYW},
-#line 42 "scripts/genksyms/keywords.gperf"
+#line 43 "scripts/genksyms/keywords.gperf"
       {"static", STATIC_KEYW},
       {""},
-#line 15 "scripts/genksyms/keywords.gperf"
+#line 16 "scripts/genksyms/keywords.gperf"
       {"__signed", SIGNED_KEYW},
-#line 30 "scripts/genksyms/keywords.gperf"
+#line 31 "scripts/genksyms/keywords.gperf"
       {"char", CHAR_KEYW},
       {""},
-#line 43 "scripts/genksyms/keywords.gperf"
+#line 44 "scripts/genksyms/keywords.gperf"
       {"struct", STRUCT_KEYW},
-#line 22 "scripts/genksyms/keywords.gperf"
-      {"__restrict__", RESTRICT_KEYW},
 #line 23 "scripts/genksyms/keywords.gperf"
+      {"__restrict__", RESTRICT_KEYW},
+#line 24 "scripts/genksyms/keywords.gperf"
       {"restrict", RESTRICT_KEYW},
-#line 33 "scripts/genksyms/keywords.gperf"
+#line 34 "scripts/genksyms/keywords.gperf"
       {"enum", ENUM_KEYW},
-#line 17 "scripts/genksyms/keywords.gperf"
+#line 18 "scripts/genksyms/keywords.gperf"
       {"__volatile", VOLATILE_KEYW},
-#line 34 "scripts/genksyms/keywords.gperf"
+#line 35 "scripts/genksyms/keywords.gperf"
       {"extern", EXTERN_KEYW},
-#line 18 "scripts/genksyms/keywords.gperf"
+#line 19 "scripts/genksyms/keywords.gperf"
       {"__volatile__", VOLATILE_KEYW},
-#line 37 "scripts/genksyms/keywords.gperf"
+#line 38 "scripts/genksyms/keywords.gperf"
       {"int", INT_KEYW},
-      {""},
-#line 31 "scripts/genksyms/keywords.gperf"
-      {"const", CONST_KEYW},
+#line 7 "scripts/genksyms/keywords.gperf"
+      {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW},
 #line 32 "scripts/genksyms/keywords.gperf"
+      {"const", CONST_KEYW},
+#line 33 "scripts/genksyms/keywords.gperf"
       {"double", DOUBLE_KEYW},
       {""},
-#line 13 "scripts/genksyms/keywords.gperf"
+#line 14 "scripts/genksyms/keywords.gperf"
       {"__inline", INLINE_KEYW},
-#line 29 "scripts/genksyms/keywords.gperf"
+#line 30 "scripts/genksyms/keywords.gperf"
       {"auto", AUTO_KEYW},
-#line 14 "scripts/genksyms/keywords.gperf"
+#line 15 "scripts/genksyms/keywords.gperf"
       {"__inline__", INLINE_KEYW},
-#line 41 "scripts/genksyms/keywords.gperf"
+#line 42 "scripts/genksyms/keywords.gperf"
       {"signed", SIGNED_KEYW},
       {""},
-#line 46 "scripts/genksyms/keywords.gperf"
+#line 47 "scripts/genksyms/keywords.gperf"
       {"unsigned", UNSIGNED_KEYW},
       {""},
-#line 40 "scripts/genksyms/keywords.gperf"
+#line 41 "scripts/genksyms/keywords.gperf"
       {"short", SHORT_KEYW},
-#line 49 "scripts/genksyms/keywords.gperf"
+#line 50 "scripts/genksyms/keywords.gperf"
       {"typeof", TYPEOF_KEYW},
-#line 44 "scripts/genksyms/keywords.gperf"
+#line 45 "scripts/genksyms/keywords.gperf"
       {"typedef", TYPEDEF_KEYW},
-#line 48 "scripts/genksyms/keywords.gperf"
+#line 49 "scripts/genksyms/keywords.gperf"
       {"volatile", VOLATILE_KEYW},
       {""},
-#line 35 "scripts/genksyms/keywords.gperf"
+#line 36 "scripts/genksyms/keywords.gperf"
       {"float", FLOAT_KEYW},
       {""}, {""},
-#line 39 "scripts/genksyms/keywords.gperf"
+#line 40 "scripts/genksyms/keywords.gperf"
       {"register", REGISTER_KEYW},
-#line 47 "scripts/genksyms/keywords.gperf"
+#line 48 "scripts/genksyms/keywords.gperf"
       {"void", VOID_KEYW},
       {""},
-#line 36 "scripts/genksyms/keywords.gperf"
+#line 37 "scripts/genksyms/keywords.gperf"
       {"inline", INLINE_KEYW},
       {""},
 #line 5 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW},
       {""},
-#line 20 "scripts/genksyms/keywords.gperf"
+#line 21 "scripts/genksyms/keywords.gperf"
       {"_Bool", BOOL_KEYW},
       {""},
 #line 6 "scripts/genksyms/keywords.gperf"
       {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW},
       {""}, {""}, {""}, {""}, {""}, {""},
-#line 38 "scripts/genksyms/keywords.gperf"
+#line 39 "scripts/genksyms/keywords.gperf"
       {"long", LONG_KEYW},
       {""}, {""}, {""}, {""}, {""},
-#line 45 "scripts/genksyms/keywords.gperf"
+#line 46 "scripts/genksyms/keywords.gperf"
       {"union", UNION_KEYW}
     };
 
index b6bec76..c75e0c8 100644 (file)
@@ -4,6 +4,7 @@ struct resword { const char *name; int token; }
 %%
 EXPORT_SYMBOL, EXPORT_SYMBOL_KEYW
 EXPORT_SYMBOL_GPL, EXPORT_SYMBOL_KEYW
+EXPORT_SYMBOL_GPL_FUTURE, EXPORT_SYMBOL_KEYW
 __asm, ASM_KEYW
 __asm__, ASM_KEYW
 __attribute, ATTRIBUTE_KEYW
index f1a5bd9..a678f09 100644 (file)
@@ -763,8 +763,14 @@ static int dummy_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
-static int dummy_socket_getpeersec(struct socket *sock, char __user *optval,
-                                  int __user *optlen, unsigned len)
+static int dummy_socket_getpeersec_stream(struct socket *sock, char __user *optval,
+                                         int __user *optlen, unsigned len)
+{
+       return -ENOPROTOOPT;
+}
+
+static int dummy_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
+                                        u32 *seclen)
 {
        return -ENOPROTOOPT;
 }
@@ -1002,7 +1008,8 @@ void security_fixup_ops (struct security_operations *ops)
        set_to_dummy_if_null(ops, socket_getsockopt);
        set_to_dummy_if_null(ops, socket_shutdown);
        set_to_dummy_if_null(ops, socket_sock_rcv_skb);
-       set_to_dummy_if_null(ops, socket_getpeersec);
+       set_to_dummy_if_null(ops, socket_getpeersec_stream);
+       set_to_dummy_if_null(ops, socket_getpeersec_dgram);
        set_to_dummy_if_null(ops, sk_alloc_security);
        set_to_dummy_if_null(ops, sk_free_security);
        set_to_dummy_if_null(ops, sk_getsid);
index b65c201..5b16196 100644 (file)
@@ -3318,24 +3318,38 @@ out:
        return err;
 }
 
-static int selinux_socket_getpeersec(struct socket *sock, char __user *optval,
-                                    int __user *optlen, unsigned len)
+static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
+                                           int __user *optlen, unsigned len)
 {
        int err = 0;
        char *scontext;
        u32 scontext_len;
        struct sk_security_struct *ssec;
        struct inode_security_struct *isec;
+       u32 peer_sid = 0;
 
        isec = SOCK_INODE(sock)->i_security;
-       if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {
+
+       /* if UNIX_STREAM check peer_sid, if TCP check dst for labelled sa */
+       if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET) {
+               ssec = sock->sk->sk_security;
+               peer_sid = ssec->peer_sid;
+       }
+       else if (isec->sclass == SECCLASS_TCP_SOCKET) {
+               peer_sid = selinux_socket_getpeer_stream(sock->sk);
+
+               if (peer_sid == SECSID_NULL) {
+                       err = -ENOPROTOOPT;
+                       goto out;
+               }
+       }
+       else {
                err = -ENOPROTOOPT;
                goto out;
        }
 
-       ssec = sock->sk->sk_security;
-       
-       err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
+       err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
+
        if (err)
                goto out;
 
@@ -3356,6 +3370,23 @@ out:
        return err;
 }
 
+static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
+{
+       int err = 0;
+       u32 peer_sid = selinux_socket_getpeer_dgram(skb);
+
+       if (peer_sid == SECSID_NULL)
+               return -EINVAL;
+
+       err = security_sid_to_context(peer_sid, secdata, seclen);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+
+
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
        return sk_alloc_security(sk, family, priority);
@@ -4344,7 +4375,8 @@ static struct security_operations selinux_ops = {
        .socket_setsockopt =            selinux_socket_setsockopt,
        .socket_shutdown =              selinux_socket_shutdown,
        .socket_sock_rcv_skb =          selinux_socket_sock_rcv_skb,
-       .socket_getpeersec =            selinux_socket_getpeersec,
+       .socket_getpeersec_stream =     selinux_socket_getpeersec_stream,
+       .socket_getpeersec_dgram =      selinux_socket_getpeersec_dgram,
        .sk_alloc_security =            selinux_sk_alloc_security,
        .sk_free_security =             selinux_sk_free_security,
        .sk_getsid =                    selinux_sk_getsid_security,
index 8e87996..c10f1fc 100644 (file)
@@ -39,6 +39,8 @@ static inline u32 selinux_no_sk_sid(struct flowi *fl)
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb);
 int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb);
+u32 selinux_socket_getpeer_stream(struct sock *sk);
+u32 selinux_socket_getpeer_dgram(struct sk_buff *skb);
 #else
 static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
 {
@@ -49,6 +51,16 @@ static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
 {
        return NF_ACCEPT;
 }
+
+static inline int selinux_socket_getpeer_stream(struct sock *sk)
+{
+       return SECSID_NULL;
+}
+
+static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb)
+{
+       return SECSID_NULL;
+}
 #endif
 
 #endif /* _SELINUX_XFRM_H_ */
index 69b9329..85e3992 100644 (file)
@@ -88,8 +88,15 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] =
        { XFRM_MSG_DELPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
        { XFRM_MSG_GETPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_READ  },
        { XFRM_MSG_ALLOCSPI,    NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_ACQUIRE,     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_EXPIRE,      NETLINK_XFRM_SOCKET__NLMSG_WRITE },
        { XFRM_MSG_UPDPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
        { XFRM_MSG_UPDSA,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_POLEXPIRE,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_FLUSHSA,     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_NEWAE,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_GETAE,       NETLINK_XFRM_SOCKET__NLMSG_READ  },
 };
 
 static struct nlmsg_perm nlmsg_audit_perms[] =
index b2af7ca..dfab6c8 100644 (file)
@@ -225,6 +225,74 @@ void selinux_xfrm_state_free(struct xfrm_state *x)
 }
 
 /*
+ * SELinux internal function to retrieve the context of a connected
+ * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security
+ * association used to connect to the remote socket.
+ *
+ * Retrieve via getsockopt SO_PEERSEC.
+ */
+u32 selinux_socket_getpeer_stream(struct sock *sk)
+{
+       struct dst_entry *dst, *dst_test;
+       u32 peer_sid = SECSID_NULL;
+
+       if (sk->sk_state != TCP_ESTABLISHED)
+               goto out;
+
+       dst = sk_dst_get(sk);
+       if (!dst)
+               goto out;
+
+       for (dst_test = dst; dst_test != 0;
+            dst_test = dst_test->child) {
+               struct xfrm_state *x = dst_test->xfrm;
+
+               if (x && selinux_authorizable_xfrm(x)) {
+                       struct xfrm_sec_ctx *ctx = x->security;
+                       peer_sid = ctx->ctx_sid;
+                       break;
+               }
+       }
+       dst_release(dst);
+
+out:
+       return peer_sid;
+}
+
+/*
+ * SELinux internal function to retrieve the context of a UDP packet
+ * based on its security association used to connect to the remote socket.
+ *
+ * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message
+ * type SCM_SECURITY.
+ */
+u32 selinux_socket_getpeer_dgram(struct sk_buff *skb)
+{
+       struct sec_path *sp;
+
+       if (skb == NULL)
+               return SECSID_NULL;
+
+       if (skb->sk->sk_protocol != IPPROTO_UDP)
+               return SECSID_NULL;
+
+       sp = skb->sp;
+       if (sp) {
+               int i;
+
+               for (i = sp->len-1; i >= 0; i--) {
+                       struct xfrm_state *x = sp->x[i].xvec;
+                       if (selinux_authorizable_xfrm(x)) {
+                               struct xfrm_sec_ctx *ctx = x->security;
+                               return ctx->ctx_sid;
+                       }
+               }
+       }
+
+       return SECSID_NULL;
+}
+
+/*
  * LSM hook that controls access to unlabelled packets.  If
  * a xfrm_state is authorizable (defined by macro) then it was
  * already authorized by the IPSec process.  If not, then